Compare commits

..

637 Commits

Author SHA1 Message Date
chai2010 b08ea25c20 math/rand 增加 GetRandomData 函数 2023-10-04 06:45:59 +08:00
chai2010 9f22163ff7 runtime 包导出引用辅助函数 2023-10-04 06:26:36 +08:00
chai2010 d335923432 完善 time 包 2023-10-03 17:37:15 +08:00
chai2010 33d3826a3c 增加 time 包 2023-10-03 08:13:58 +08:00
chai2010 20fe893009 重构 os 包的 args 和 envs 处理 2023-10-03 07:38:52 +08:00
chai2010 7a8bb12296 添加 vscode 工作区文件 2023-10-03 06:33:49 +08:00
chai2010 f361d89241 syscall/wasi 增加时间函数 2023-10-02 18:27:30 +08:00
chai2010 e3e895acb2 完善 math/rand 包 2023-10-02 17:16:18 +08:00
chai2010 7484fe5903 增加 math/rand 包 2023-10-02 17:08:50 +08:00
chai2010 a5f59fa675 strings 包补充测试 2023-10-02 16:29:52 +08:00
chai2010 b73b48f874 fix test 2023-09-28 20:47:40 +08:00
chai2010 adc0a1a791 完善 image/bmp 包 2023-09-28 20:36:20 +08:00
chai2010 af5f8eca1d 完善 image 包 2023-09-28 00:11:58 +08:00
chai2010 fa7fa0ff8c image 包调整 2023-09-27 17:45:37 +08:00
chai2010 275e0124ad Merge branch 'master' of gitee.com:wa-lang/wa 2023-09-27 13:17:38 +08:00
chai2010 8913805d36 添加 encoding/qrcode 包 2023-09-27 13:17:11 +08:00
3dgen 4b770dc521 修正注释格式 2023-09-26 22:00:04 +08:00
chai2010 6290692a7b 添加 math/gf256 包 2023-09-26 20:41:40 +08:00
chai2010 7ef84c74ae 恢复 strconv 包 2023-09-26 20:41:15 +08:00
3dgen 740948bcbb wat 输出使用 strings.Builder 代替字符串加法 2023-09-26 15:49:22 +08:00
3dgen b37d27cb47 全局变量初始化方式变更 2023-09-21 15:13:56 +08:00
3dgen 1194904bd8 Merge branch 'backend_wasm' 2023-09-18 15:40:06 +08:00
3dgen 9b07a5afea 优化结构体成员变量的标识符名称 2023-09-18 15:39:22 +08:00
xxx b8b6c5918c fix: svg 2023-09-17 16:45:42 +08:00
chai2010 7979cc4ff5 fix test 2023-09-16 21:15:05 +08:00
chai2010 e10dd3ffc2 补充 sort/bufio 等标准库 2023-09-15 20:22:39 +08:00
chai2010 daffa01c7b 裁剪 strconv 包 2023-09-15 20:19:35 +08:00
chai2010 7bea718e2e zz 2023-09-15 08:32:26 +08:00
chai2010 c7e79d4fe6 增加 base64 包 2023-09-15 08:27:56 +08:00
chai2010 510af7ef6c 标准库增加 hex 包和部分 binary 包函数 2023-09-14 19:35:23 +08:00
chai2010 562a7b5e59 恢复被临时注释的代码 2023-09-14 19:34:52 +08:00
chai2010 dca847159d 更新 readme 2023-09-14 06:05:37 +08:00
3dgen f69e21a85e 修正结构体包含自身引用导致的栈溢出 2023-09-12 17:42:04 +08:00
3dgen 3c34f0db3b 补充字符串<=等比较操作 2023-09-12 16:46:15 +08:00
3dgen 1627f93edb Merge branch 'backend_wasm' 2023-09-12 14:52:29 +08:00
3dgen c7210adcec 函数调用参数传递时引用的rc约定修改 2023-09-12 14:51:30 +08:00
chai2010 2daf947ea9 添加 hash/crc64 包 2023-09-10 12:56:49 +08:00
chai2010 29767745d5 添加 hash 和 crc32 包 2023-09-10 12:36:30 +08:00
chai2010 3efa7341c6 strings 包补充函数 2023-09-10 11:35:54 +08:00
chai2010 7d6cc8925d zz 2023-09-10 07:49:34 +08:00
chai2010 4fea6923f3 strings 包补充函数 2023-09-10 07:48:22 +08:00
chai2010 b645f8d8e4 strings 包增加函数 2023-09-09 22:01:08 +08:00
chai2010 481f6878c3 unicode/utf8 包增加 AppendRune 函数 2023-09-09 21:37:41 +08:00
chai2010 fc0314a54b strconv 包补齐函数 2023-09-09 20:20:17 +08:00
chai2010 c312135ccb bytes 包补充函数 2023-09-09 17:24:35 +08:00
chai2010 c0b58d678b bytes 包补充函数 2023-09-09 08:47:23 +08:00
3dgen afddc41fc9 消除部分全局变量 currentModule 的使用 2023-09-07 16:39:13 +08:00
chai2010 6daa480a76 merge 2023-09-05 22:00:43 +08:00
chai2010 5296334131 ssa 删除废弃代码 2023-09-05 21:58:54 +08:00
3dgen 32ab9ab3d3 Merge branch 'master' into backend_wasm 2023-09-05 11:22:53 +08:00
3dgen f3476b281f Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-09-05 11:22:02 +08:00
3dgen 21d2a2c7cc 支持重用类型,第二阶段 2023-09-05 11:21:37 +08:00
chai2010 48b61ab9ea zz 2023-09-05 08:17:12 +08:00
chai2010 e1b61af9af 实现简版 wa doc 子命令 2023-09-04 23:57:09 +08:00
3dgen e8c9eefaae 支持重用类型,第一阶段 2023-09-04 20:48:17 +08:00
chai2010 d9af33bb75
!14 math/big 补充修改
Merge pull request !14 from 啊bc/master
2023-08-31 12:59:30 +00:00
chai2010 6cbf43a141 bytes 包完善测试 2023-08-31 20:53:07 +08:00
trueabc 6207648869 math.big测试补充
1. 全局var修改为global
2. 单元测试修改为assert, 简化部分测试代码
3. 版权信息修改
2023-08-31 19:35:36 +08:00
3dgen ab40ca7aec 补充单 rune 转 string 2023-08-31 11:00:08 +08:00
3dgen d6c5c21a68 Merge branch 'backend_wasm' 2023-08-30 22:06:07 +08:00
3dgen 53f9d895c8 修正 runtime 的 utf8 相关常量定义位置错误 2023-08-30 22:05:31 +08:00
chai2010 deaa7f87c0 unicode/utf8 补充测试 2023-08-30 21:26:06 +08:00
3dgen 33f6724e76 wir.Module 增加无类型整数类型(为重构做准备) 2023-08-30 17:03:59 +08:00
3dgen a03e731d98 补完 string 与 []rune 的相互转换 2023-08-30 16:43:05 +08:00
3dgen 7f484df65b wasi 目标下支持打印 unicode rune 2023-08-30 11:20:24 +08:00
3dgen 37299bc094 Merge branch 'master' into backend_wasm 2023-08-30 11:06:29 +08:00
3dgen 6157ec2a23 静态数据段避开栈 2023-08-30 10:01:17 +08:00
chai2010 e3145d88e8 unicode/utf8 添加 EncodeRuneString 函数 2023-08-29 23:18:51 +08:00
3dgen 1329c4a0f2 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-08-29 22:48:05 +08:00
3dgen 6017de5bec Merge branch 'backend_wasm' 2023-08-29 22:47:58 +08:00
3dgen ee56900e3e 增加字符串按 rune 遍历(for range迭代) 2023-08-29 22:47:37 +08:00
chai2010 e556debf78 math/big 标准库生效 2023-08-29 21:55:53 +08:00
丁尔男 90a0504467
!13 凹语言大整数库
Merge pull request !13 from 啊bc/master
2023-08-29 12:29:48 +00:00
trueabc d4dd989861 wa大整数运算 2023-08-29 19:19:48 +08:00
xxx b257139578 chore: add wa wasm zip 2023-08-28 14:54:44 +08:00
chai2010 fe8be85b56 unicode/utf8 包补充测试 2023-08-27 07:34:00 +08:00
3dgen f4b3765204 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-08-26 17:37:23 +08:00
3dgen ae1ddc3798 修正有符号数右移时符号位错的问题 2023-08-26 17:36:50 +08:00
chai2010 a27b5d5eaa unicode/utf8 包补充测试 2023-08-25 22:56:35 +08:00
chai2010 4277b7f28d Merge branch 'master' of gitee.com:wa-lang/wa 2023-08-25 07:07:33 +08:00
chai2010 c06198e1c6 bytes 包补充测试 2023-08-25 07:06:31 +08:00
3dgen cd3645e40a 导出runtime.Release 2023-08-24 21:54:10 +08:00
3dgen b4eb99057b Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-08-24 20:53:20 +08:00
3dgen 619098ff90 导出waHeapAlloc、waHeapFree 2023-08-24 20:53:12 +08:00
chai2010 ee0c4c718d bytes 包补充函数和测试 2023-08-22 20:13:59 +08:00
chai2010 6557bef692 补充测试 2023-08-21 19:36:09 +08:00
chai2010 91ecd0c297 bytes 包补充测试 2023-08-21 07:26:36 +08:00
chai2010 69aaa0d61f bytes 包补充函数和测试 2023-08-21 06:52:52 +08:00
chai2010 34dbf326f0 bytes 测试代码微调 2023-08-20 22:26:43 +08:00
3dgen 28ba454b25 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-08-20 20:56:55 +08:00
3dgen 7cb70a8d9b 修正[low:high:max]语法未处理max的问题 2023-08-20 20:56:45 +08:00
chai2010 14a0ac062c bytes 包更多函数和测试 2023-08-20 11:24:10 +08:00
chai2010 431facd2d7 bytes 包更多测试 2023-08-20 07:10:53 +08:00
chai2010 80bc37c983 增加 bytes.Compare 函数和测试 2023-08-19 20:07:04 +08:00
chai2010 baf0f798e2 fix bytes test 2023-08-18 18:47:47 +08:00
3dgen ac3d716b58 强制检查:值类型不能赋值给非空接口 2023-08-18 15:09:08 +08:00
3dgen 7a4d1e6b8a 修正bytes.TestReaderCopyNothing测试 2023-08-18 14:53:37 +08:00
3dgen 740912a32e 结构体匿名嵌入时忽略包名 2023-08-18 14:52:50 +08:00
3dgen 1c9855f2c7 数据段留16字节安全区 2023-08-18 14:51:31 +08:00
chai2010 c1b8fc1e62 bytes.Reader 增加测试 2023-08-18 07:20:14 +08:00
chai2010 61c1638260 bytes 包添加 Reader 实现 2023-08-18 06:58:17 +08:00
chai2010 fb6798f38d 修复贪吃蛇发布脚本 2023-08-17 07:38:22 +08:00
chai2010 88316e15a4 bytes 包的 Buffer 补充测试 2023-08-16 22:17:00 +08:00
chai2010 c5ce3a5e54 标准库增加 buffer 实现, 尚不能使用 2023-08-16 20:57:03 +08:00
chai2010 9e0cc0f9ec 更新 readme 2023-08-12 07:53:30 +08:00
chai2010 8865306912 调试模式输出符号表 2023-08-12 07:27:15 +08:00
chai2010 154dc2d591 更新 变更日志 2023-08-11 18:56:19 +08:00
3dgen bff4fd1883 wat目标输出顺序固定 2023-08-10 20:05:10 +08:00
3dgen 7ee8e6279b heap_base 对齐到16 2023-08-10 16:27:05 +08:00
3dgen 36381d5adc 修正接口查询 2023-08-10 11:12:52 +08:00
3dgen 40385e8cd2 修正heap_base常量 2023-08-09 22:14:36 +08:00
chai2010 fc25830c3a wa test 增加 -run 参数, 用于指定测试的函数 2023-08-08 23:00:06 +08:00
chai2010 fb6b8c64da 补充 mvp 缺少的函数 2023-08-08 22:22:02 +08:00
chai2010 2678407bfb 更新版本 2023-08-08 20:24:11 +08:00
chai2010 744e345703 接口打印格式微调 2023-08-08 20:17:58 +08:00
3dgen c0085c32ec zz 2023-08-08 19:49:01 +08:00
3dgen 9f8486566b Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-08-08 08:49:39 +08:00
3dgen 3693430e17 接口打印 2023-08-08 08:48:48 +08:00
chai2010 66113f0f2c math/bits: 完善 panic 测试 2023-08-06 11:10:36 +08:00
chai2010 e53ddc2616 wa test 完善 panic 测试 2023-08-06 07:30:43 +08:00
chai2010 4ca0062f02 wa test 支持异常测试 2023-08-06 07:13:42 +08:00
chai2010 c2ceecece6 math/bits 更多测试 2023-08-05 14:28:29 +08:00
chai2010 4f04afc2d1 math/bits 更多测试 2023-08-05 14:04:08 +08:00
chai2010 37aabb322d readme 增加手册链接 2023-08-05 08:25:40 +08:00
chai2010 6f3da4c874 math/bits 包补充测试 2023-08-05 08:17:58 +08:00
chai2010 9c615cf054 math/bits 补充测试 2023-08-05 07:44:25 +08:00
chai2010 dd68b06469 wa test 修复子包路径错误 2023-08-05 07:17:51 +08:00
chai2010 d12c948e79 修复 waPrintU64 参数类型错误 2023-08-04 19:51:35 +08:00
chai2010 fb2ead4b07 Merge branch 'master' of gitee.com:wa-lang/wa 2023-08-04 19:49:15 +08:00
chai2010 931a8a7eb4 zz 2023-08-04 19:47:52 +08:00
3dgen 338ffe0288 修正 i64、u64 在默认目标下打印错误 2023-08-04 10:18:34 +08:00
chai2010 17ee7a95e2 修复 action 2023-08-03 21:57:16 +08:00
chai2010 8a020beaca 标准库增加 builtin 包 2023-08-03 21:37:28 +08:00
chai2010 fa740ac138 实现 panic 2023-08-03 20:08:50 +08:00
chai2010 3c382a5cca 准备更多 wasm 辅助函数 2023-08-03 20:04:35 +08:00
chai2010 472677ce8b wasm 二进制模块包增加部分函数 2023-08-02 19:49:41 +08:00
chai2010 3a69f29d32 标准库添加 archive/txtar 包, 还不能用 2023-08-02 19:40:37 +08:00
chai2010 376369693c 更新 wa.mod 注释 2023-08-01 22:31:48 +08:00
chai2010 7f4e6d11dc 修复 wa.mod 2023-08-01 22:24:49 +08:00
chai2010 1ed1108a3d 更新 wa.mod 文件 2023-08-01 22:16:49 +08:00
chai2010 eea10fb266 简化 mod 文件, 采用 ini 格式 2023-08-01 20:26:11 +08:00
chai2010 90458b4485 修复 action chrome 失败 2023-07-31 20:33:44 +08:00
chai2010 9f54c60853 定义函数省略空参数 2023-07-31 20:24:52 +08:00
chai2010 708fa769b0 全局用 global 关键字 2023-07-31 20:20:55 +08:00
chai2010 5024b8a351 统一 print 相关函数; 汇编函数增加包路径前置 2023-07-31 20:20:09 +08:00
chai2010 2bb7def2c4 完善 runtime 的 print 函数 2023-07-30 20:06:19 +08:00
chai2010 46c94732a7 zz 2023-07-30 01:19:41 +08:00
chai2010 bf9ca015f5 wa logo 增加 svg 格式 2023-07-30 01:10:24 +08:00
chai2010 7eb0fabac0 标准库 strconv 搬运更多函数, 全部表格导致生成目标急剧增大 2023-07-30 00:49:53 +08:00
chai2010 0a813a7e24 标准库搬运更多 math 函数 2023-07-30 00:10:03 +08:00
3dgen 1dc7132856 浮点按位直转整数 2023-07-29 23:11:13 +08:00
chai2010 c8180183be wasi: 实现临时版本 f64 打印 2023-07-29 04:40:33 +08:00
chai2010 8ca5774db5 根据 MVP 手册内容完善 wa 命令 2023-07-29 02:03:04 +08:00
chai2010 c0d1e8bd73 goreleaser: main 分支是个错误, 修复 2023-07-27 19:53:35 +08:00
chai2010 ae4622bb60 配置打包脚本 2023-07-27 19:22:00 +08:00
chai2010 9dc0ff6b3c 修复 github action 2023-07-26 22:04:03 +08:00
chai2010 b65c8ff5d4 首个 MVP 版本 2023-07-26 21:59:05 +08:00
3dgen b4c0b7c319 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-07-26 20:17:39 +08:00
3dgen 24e76b871e zz 2023-07-26 20:17:30 +08:00
chai2010 7c1573fbf3 wa 命令代码重构优化 2023-07-26 20:06:56 +08:00
chai2010 a65f4d1a6b wa build 和 run 命令调整输出文件默认路径 2023-07-25 07:07:01 +08:00
chai2010 c79fbbc593 wa 命令调整目录结构 2023-07-24 21:49:31 +08:00
chai2010 d4c997cc1e 完善 wa init 命令参数检查 2023-07-23 09:11:23 +08:00
chai2010 02345b4cc3 修复 wa init 命令 2023-07-22 21:53:58 +08:00
chai2010 f6c8d65d86 继续 wa 命令行代码目录重构 2023-07-22 21:21:00 +08:00
chai2010 a785c977c1 wa 命令行代码目录重构 2023-07-22 16:50:18 +08:00
chai2010 fe27741c41 wa 命令行增加版权和网站信息 2023-07-22 14:54:00 +08:00
chai2010 340a1aa10d 简化 wa 命令行界面 2023-07-22 14:26:01 +08:00
chai2010 ca0b095313 重新 fmt 例子 2023-07-20 19:21:07 +08:00
chai2010 fc10449a76 完善 fmt, 局部变量采用凹语言格式 2023-07-20 19:20:17 +08:00
3dgen 8e2880af99 修正函数值比较 2023-07-19 15:47:46 +08:00
chai2010 13c849ddfe 临时修补 chrome 目标失败的例子 2023-07-17 23:34:26 +08:00
3dgen 0e0c4a7a2a 修正 assert 参数0 类型判定错误 2023-07-17 23:18:45 +08:00
3dgen cdb0352bfe 修正类型断言返回类型错误 2023-07-17 22:52:01 +08:00
chai2010 acc3779a0a 改进 fmt 子命令 2023-07-16 21:39:21 +08:00
3dgen e644df0204 修正 bool 未识别为 num 2023-07-13 11:14:53 +08:00
3dgen 78f7b71fdb Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-07-13 10:50:21 +08:00
3dgen 7a06fb5289 wir 增加原生 bool 类型 2023-07-13 10:50:09 +08:00
chai2010 03ec841701 WAIC2023 志愿者贡献点 2023-07-11 18:56:55 +08:00
chai2010 bd7f9f25d5 修复 mvp 下 example 测试特性 2023-07-07 23:19:06 +08:00
chai2010 e9b52e3e8a 标准库增加 apple 包, 支持 mvp 环境测试 test 命令 2023-07-05 23:36:13 +08:00
chai2010 9558393432 临时保存 2023-07-05 22:15:59 +08:00
3dgen 33fa620d2d 消除部分重复常量字符串 2023-07-04 18:01:32 +08:00
3dgen 72136e07ca 左右移位操作问题修正 2023-07-04 17:33:04 +08:00
chai2010 2f5995a2d8 panic 参数限制为 string 2023-07-02 14:19:32 +08:00
3dgen 92ec97e8ab 增加 buildin.ssa:wrapnilchk 2023-07-01 21:34:52 +08:00
3dgen decb015cda 添加! ^ 单目操作符 2023-07-01 17:51:00 +08:00
3dgen f714517661 Merge branch 'master' into backend_wasm 2023-07-01 10:06:52 +08:00
3dgen f018eb7c71 改进整数打印 2023-07-01 10:06:09 +08:00
chai2010 43ca453794 搬运 math/bits 包 2023-06-30 20:14:23 +08:00
chai2010 c957ea0f7d 移植部分 image 实现, 未完 2023-06-30 19:52:55 +08:00
chai2010 48db574ba4 去掉内部的 ascii 转化表, 减少输出 wat 体积 2023-06-30 19:08:51 +08:00
chai2010 7b220f4b9a 简化 std 测试方式 2023-06-30 18:37:46 +08:00
chai2010 b0839d7a2c 增加 版本号 文件 2023-06-28 22:20:25 +08:00
chai2010 dfa6b44319 屏蔽 parser 失败的测试 2023-06-28 19:32:25 +08:00
chai2010 0a5a671f5d CI 添加 fmt 并包含更多测试 2023-06-28 19:28:16 +08:00
chai2010 86a784e019 fmt 支持 global 关键字 2023-06-28 02:07:11 +08:00
chai2010 edaa2dd380 完善 syntax 语法格式 2023-06-28 01:17:26 +08:00
chai2010 9b9870b2f9 完善 run 命令对相对路径文件的支持 2023-06-28 01:12:44 +08:00
chai2010 08da080269 完善 MVP 目标定义 2023-06-27 23:20:25 +08:00
3dgen 14d79a0b71 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-06-27 21:44:58 +08:00
3dgen 6cf3f999e0 增加mvp os 2023-06-27 21:40:40 +08:00
chai2010 a61c9d839c 修复并完善 fmt 命令 2023-06-27 07:22:06 +08:00
chai2010 db9d81ad4d 完善 wat 导出的中文名字处理 2023-06-27 00:58:24 +08:00
chai2010 bcadb47048 删除 playground 中输出的调试信息 2023-06-26 23:45:02 +08:00
chai2010 52f3c77d37 改进 wz 语法支持 2023-06-26 23:32:52 +08:00
chai2010 0a31dc803b 增加代码文件类型识别语法 2023-06-26 22:40:51 +08:00
3dgen 8201374e17 zz 2023-06-26 11:03:11 +08:00
3dgen 61571ac7b0 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-06-25 21:29:57 +08:00
3dgen be17597bdb 添加手册-2.1 2023-06-25 21:29:43 +08:00
chai2010 783d26fc35 本地 play 支持凹中文 2023-06-25 20:13:58 +08:00
chai2010 ca4bc40a3b wa 命令行内置简版 play 2023-06-23 21:37:53 +08:00
chai2010 3a416ed2ac 重构 wa 命令代码目录结构 2023-06-22 19:21:46 +08:00
chai2010 106cf4c828 完善测试功能 2023-06-22 14:10:47 +08:00
chai2010 5319e5a5ed test 切换到 wazero 包装函数 2023-06-22 11:05:19 +08:00
chai2010 473e0fcfe6 切换到新 waroot 目录, 删除旧目录 2023-06-22 09:56:12 +08:00
chai2010 4aa6f29533 修复 run 子命令 2023-06-22 07:34:46 +08:00
chai2010 663c4ba3c8 更新 readme 2023-06-21 08:36:18 +08:00
chai2010 61d8ae100e wayacc 输出代码改用凹语言风格 2023-06-21 08:34:11 +08:00
chai2010 a72a04eaec 启用新包装的 wabt 函数 2023-06-21 07:42:05 +08:00
chai2010 de4655625f 优化 api.RunCode 2023-06-21 07:18:09 +08:00
chai2010 d93a368db5 包装 wabt 和 wazero 2023-06-20 23:20:22 +08:00
chai2010 a21a345832 parser 屏蔽 i8 和 i16 2023-06-19 21:41:02 +08:00
chai2010 bce3aefc36 snake 避免使用 i8 类型, 暂不支持 2023-06-19 21:25:55 +08:00
chai2010 0b18402827 Merge branch 'master' of gitee.com:wa-lang/wa 2023-06-19 21:11:41 +08:00
chai2010 013ecb93ec 初步支持 global, AST 暂时作为 var 处理 2023-06-19 21:10:22 +08:00
3dgen b231910a56 Merge branch 'backend_wasm' 2023-06-19 17:30:30 +08:00
3dgen ad1a12c93b 屏蔽i8、i16类型 2023-06-19 15:11:43 +08:00
chai2010 199c5f366b 继续迁移 waroot 2023-06-18 23:31:48 +08:00
chai2010 627abe9ef2 删除 Windows 下 exe 的图标 2023-06-18 17:11:40 +08:00
chai2010 0d4097dff6 完善 waroot 目录 2023-06-18 17:03:41 +08:00
chai2010 d8f793798e 梳理凹语言安装对应的目录结构 2023-06-18 10:56:44 +08:00
chai2010 6a26c56444 例子代码改为短变量声明风格 2023-06-17 23:19:22 +08:00
chai2010 e50b09b8eb 支持简短局部变量声明语法 2023-06-17 21:17:26 +08:00
chai2010 a94481008e zz 2023-06-16 21:12:37 +08:00
chai2010 4fa3419bf7 zz 2023-06-16 21:02:05 +08:00
3dgen c26a74d3b9 更新贡献点列表,增加贡献点转账日志 2023-06-16 11:17:39 +08:00
chai2010 38243912d4 优化单元测试性能 2023-06-16 06:40:55 +08:00
chai2010 9fb4ddc9c1 修复 build wasm 子命令 2023-06-15 19:24:26 +08:00
chai2010 c1cd6a8e59 删除冗余代码 2023-06-15 19:19:04 +08:00
chai2010 4b5efe60c3 wabt 回退到 native 版本 2023-06-15 19:17:25 +08:00
3dgen 01432b1d59 1.去除一些没有实际作用的指令;
2.缩短使用频率最高的内部标识符
2023-06-15 14:32:13 +08:00
3dgen 2da1c6e741 去除不必要的初始化 2023-06-14 14:38:35 +08:00
chai2010 4bb260a1d2 strconv 完善测试 2023-06-13 23:39:02 +08:00
chai2010 09fdcecd00 添加 bytes 包 2023-06-13 19:25:01 +08:00
3dgen bc13e5ae2d 修正接口互查 2023-06-10 10:15:28 +08:00
chai2010 6b88c18440 补充类型断言失败的例子 2023-06-09 23:49:51 +08:00
chai2010 c13d6105dc 更多 errors 测试, 失败 2023-06-09 21:59:21 +08:00
3dgen 7f70a11954 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-06-09 21:35:28 +08:00
3dgen b4d1b285ad 打印接口地址 2023-06-09 21:35:16 +08:00
chai2010 ca2669a243 ci 添加 errors 包测试 2023-06-09 21:27:12 +08:00
chai2010 31e72fa086 更多 ci 测试 2023-06-09 21:22:32 +08:00
chai2010 48e0f65fa7 完善 ci 测试 2023-06-09 21:11:22 +08:00
3dgen 7e5593b33d 支持内置 copy 函数 2023-06-09 15:51:17 +08:00
3dgen 8d0808160b zz 2023-06-08 23:39:32 +08:00
3dgen fed1a25a38 支持 ^& 2023-06-08 22:50:16 +08:00
3dgen babd47c447 1.增加位运算
2.修正数字类型转换指令至新版wasm标准
2023-06-08 20:53:27 +08:00
3dgen 9b063fdf00 补充int转rune 2023-06-07 23:37:03 +08:00
3dgen 52f85d9b40 补充类型转换指令 2023-06-07 23:20:27 +08:00
3dgen 41c66eb123 多参数打印加空格分隔 2023-06-07 16:35:53 +08:00
3dgen 6ce77e2aaf 支持常用类型转换 2023-06-07 16:29:40 +08:00
3dgen d0f333dd79 支持nil值初始化空接口 2023-06-07 10:40:15 +08:00
3dgen 8a0d245180 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-06-07 10:29:34 +08:00
3dgen 0fa2cfa3b1 支持非标类型相等操作 2023-06-07 10:29:05 +08:00
chai2010 6313174bbf 更新标准库列表 2023-06-03 21:26:04 +08:00
chai2010 5a5d01f7a9 标准库添加 image/bmp 包 2023-06-03 21:18:31 +08:00
chai2010 ef4d8cc0d0 添加 image 包 2023-06-03 21:09:41 +08:00
chai2010 ead196142d 根目录只保留一个 main 名字的源文件, 方便执行时补全 2023-06-03 20:59:08 +08:00
chai2010 659137b156 添加 image/color 标准库 2023-06-03 19:02:52 +08:00
chai2010 6ec3274366 Merge branch 'master' of gitee.com:wa-lang/wa 2023-06-03 14:07:50 +08:00
chai2010 9989d25590 添加 binrary 标准库 2023-06-03 14:05:47 +08:00
chai2010 291b1e0039
!12 修改中文解析器,将【启】函数名映射到main名称
Merge pull request !12 from 衍星居士/frontend_wz
2023-06-03 05:48:59 +00:00
衍星居士 034be0d214 修改中文解析器,将【启】函数名映射到main名称,后端统一用main来处理 2023-06-03 05:38:34 +00:00
衍星居士 4c29af9ece 添加了凹中文版的语法文档(未完成) 2023-06-03 05:38:34 +00:00
chai2010 122a60606c strconv 添加 bool 函数 2023-06-03 13:15:39 +08:00
衍星居士 595284752c 修改api.go,添加中文版【启】函数的支持 2023-06-03 04:02:41 +08:00
chai2010 afb55fa475 添加 io 标准库 2023-06-03 08:28:17 +08:00
chai2010 ced44de321 移植 strconv 更多函数 2023-06-03 08:00:59 +08:00
chai2010 6fbc4e7dc9 添加 unicode 标准库 2023-06-03 07:49:23 +08:00
chai2010 8b5c03f633 增加 unicode/utf8 标准库 2023-06-03 07:31:59 +08:00
3dgen e5ed1490ab Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-06-02 21:43:56 +08:00
3dgen d339f1a262 zz 2023-06-02 21:43:30 +08:00
chai2010 9e01ec6025 添加 errors 标准库 2023-06-02 21:22:44 +08:00
3dgen 6b54f4f2b3 Merge branch 'backend_wasm' 2023-06-02 21:10:19 +08:00
3dgen 6664ced0fc 补充i64、u64常量值 2023-06-02 21:09:38 +08:00
chai2010 a909302ed2 添加 strconv.Itoa 测试 2023-06-02 21:02:32 +08:00
chai2010 672daee8e1 regexp 增加测试 2023-06-02 20:18:26 +08:00
3dgen 8981da7fc8 fix typo 2023-06-02 17:45:59 +08:00
3dgen 722753c9d6 SPtr类型退回Ref 2023-06-02 11:55:47 +08:00
3dgen 2822949d6d Merge branch 'backend_wasm' 2023-06-02 10:54:10 +08:00
3dgen c3b4e3bf4d 支持复制类型 2023-06-02 10:53:13 +08:00
chai2010 317a57b6e4 更新 readme 2023-06-02 10:44:07 +08:00
chai2010 5af6cc365b 更新 readme 2023-06-02 10:34:38 +08:00
chai2010 67650658c7 fmt.Println 支持可变参数 2023-06-02 10:24:17 +08:00
chai2010 15244f9252 添加 surface 例子 2023-06-02 10:19:12 +08:00
chai2010 3f601cc526 规范使用基础类型的名字 2023-06-02 10:10:09 +08:00
chai2010 0f564e94ec 添加简版 regexp 包实现 2023-06-01 21:20:30 +08:00
3dgen 0df1b138e5 更新贡献者名单 2023-06-01 10:20:39 +08:00
chai2010 998e732710 完善 fmt 命令 2023-05-28 16:15:37 +08:00
3dgen 94ee10be7a Merge branch 'backend_wasm'
# Conflicts:
#	_examples/interface_named.wa
2023-05-28 10:30:45 +08:00
3dgen ee0ba1a42f 更新接口例子 2023-05-28 10:28:38 +08:00
chai2010 093eb2b5ab 完善 ci 测试 2023-05-27 11:24:53 +08:00
chai2010 147fb2c478 完善 ci 测试 2023-05-27 11:19:03 +08:00
chai2010 23cbd05edf 添加 _examples 到 ci 测试 2023-05-27 11:04:47 +08:00
chai2010 7cabaa4ade 完善 wago 方法解析 2023-05-27 09:51:48 +08:00
chai2010 09ec7f4a53 收紧对可选 wago 语法支持 2023-05-27 07:27:00 +08:00
chai2010 763c584b8f 减少外部依赖 2023-05-27 06:51:31 +08:00
chai2010 22c881488c 单元测试支持 output 验证 2023-05-27 06:47:47 +08:00
chai2010 8e8ebcad21 增加 example 测试 2023-05-26 23:17:43 +08:00
chai2010 8444ca2a4e Merge branch 'master' of gitee.com:wa-lang/wa 2023-05-26 21:54:03 +08:00
chai2010 337af63d0b 修复 wa build 命令 2023-05-26 21:53:07 +08:00
3dgen baab5ea293 修正引用类型名称 2023-05-26 10:25:12 +08:00
3dgen 5f6f65c826 Merge branch 'backend_wasm' 2023-05-26 10:22:53 +08:00
3dgen a1bc606678 支持空接口中装入值 2023-05-26 10:21:20 +08:00
chai2010 086bfa84eb wat2wasm 改用 wasm 版本; 更新变更日志 2023-05-26 01:03:03 +08:00
3dgen d55e65ab12 支持匿名接口 2023-05-25 17:03:52 +08:00
3dgen a5a6396eb5 支持匿名结构体 2023-05-25 16:03:08 +08:00
3dgen 3a9f054a88 统一运行时内部标识符到 wa.runtime. 2023-05-25 11:20:37 +08:00
chai2010 b7fb5ff56c wa test 支持标准库 2023-05-25 00:32:32 +08:00
3dgen e9b7b64318 Merge branch 'backend_wasm' 2023-05-24 17:37:01 +08:00
3dgen 85fac2c64b 更新接口例子 2023-05-24 17:36:36 +08:00
3dgen 0cfd08668a Merge branch 'backend_wasm' 2023-05-24 17:31:21 +08:00
3dgen 0778c143d4 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-05-24 17:31:07 +08:00
3dgen 58362e7bc1 1、支持I2I
2、临时屏蔽类型信息注入
2023-05-24 17:30:18 +08:00
3dgen 4c554712cc 支持接口转具体类型 2023-05-22 20:58:03 +08:00
chai2010 96e76c2988 添加 png 格式 logo 2023-05-20 18:18:33 +08:00
3dgen 61ce7c13cd 增加引用类型 2023-05-18 16:58:09 +08:00
3dgen ce6cdae538 Ref类型更名为SPtr 2023-05-18 15:57:41 +08:00
3dgen 2de29d428a Merge branch 'backend_wasm' 2023-05-18 11:22:28 +08:00
3dgen cd33d191af Todo: 闭包的类型信息 2023-05-18 11:03:44 +08:00
3dgen 4d6d71c72d .underlying、runtime等内部结构体信息不导出 2023-05-18 10:57:25 +08:00
3dgen 040ca084eb 注入类型信息(未测试) 2023-05-18 09:57:25 +08:00
3dgen 6e37e3c886 1、变更wir.Module中关于函数类型的定义方法
2、运行时类型信息注入(WIP)
2023-05-08 20:16:39 +08:00
chai2010 911e1bc426 loader: 完善测试和汇编相关的结构, 并完善测试信息解析 2023-05-07 21:35:06 +08:00
chai2010 a5f7fd3879 lsp 更新保存 2023-05-06 00:45:02 +08:00
chai2010 5862f8e68b 添加 jsonrpc2 依赖 2023-05-06 00:04:53 +08:00
chai2010 be0f86a31e lsp: 完善 rpc 实现 2023-05-02 09:07:59 +08:00
chai2010 fbb46bdfd7 准备 lsp 依赖的 rpc 辅助包 2023-05-01 21:56:47 +08:00
chai2010 5d44a69c62 完善 wat 解析包 2023-05-01 21:33:32 +08:00
chai2010 f1a02f30f0 开始建立 wat 子包 2023-05-01 21:01:47 +08:00
chai2010 ab797adf23 增加通过 api 执行 wz 例子(尚不能运行) 2023-05-01 18:56:31 +08:00
chai2010 ecb3f3a3b1 构造 play 测试代码, 对比 js 和 本地环境运行差异 2023-04-29 07:54:43 +08:00
chai2010 563e6d040a 打印 ast 的 map 时保序 2023-04-29 07:35:00 +08:00
3dgen e972d48df6 zz 2023-04-26 16:09:29 +08:00
chai2010 24da36739c 配置 node 执行 wasm 环境 2023-04-24 22:25:32 +08:00
3dgen 6419cbd04b Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-04-24 20:19:17 +08:00
3dgen da1aa231ad Merge branch 'backend_wasm' 2023-04-24 20:19:10 +08:00
3dgen 8cc5b02f7e itab 相关功能移至 wir 层 2023-04-24 20:18:03 +08:00
chai2010 ae235b6177 Merge branch 'master' of gitee.com:wa-lang/wa 2023-04-23 23:44:16 +08:00
chai2010 1799cec6e0 准备调试 play 辅助代码 2023-04-23 23:42:15 +08:00
3dgen 02cbda20d2 Merge branch 'backend_wasm' 2023-04-19 20:56:43 +08:00
3dgen 9fe5f62aad 优化 wir.Struct 类型的生成逻辑 2023-04-19 20:55:51 +08:00
chai2010 4a6664057c 删除 fn 关键字, 已经过了过渡期 2023-04-18 08:08:12 +08:00
chai2010 2e26d7e428 修复遗留的 fn 废弃关键字 2023-04-16 10:20:10 +08:00
chai2010 562c42cd78 临时调整测试 2023-04-16 08:44:53 +08:00
chai2010 cbcdb25cca 修复 loader 错误 2023-04-16 08:26:25 +08:00
chai2010 215c082e3a 修复局部代码 2023-04-16 08:09:43 +08:00
chai2010 289bfb76f1 恢复 chrome 平台支持 2023-04-16 08:05:27 +08:00
chai2010 c8f363f16d 修复 md 格式问题 2023-04-15 19:51:46 +08:00
chai2010 2093af5c69
!11 添加了中文版语法的说明文档
Merge pull request !11 from 衍星居士/frontend_wz
2023-04-15 00:16:48 +00:00
衍星居士 3026873a0d 修改中文版示例的格式 2023-04-15 02:05:35 +08:00
衍星居士 f5c19b5659 添加中文版语法设计的说明文档 2023-04-15 02:03:12 +08:00
3dgen 17493a3afb interface 优化:Method移入wir.ValueType 2023-04-14 17:13:39 +08:00
3dgen b83d40c0c3 修正类型驱动方法生成时循环调用的问题 2023-04-14 11:20:04 +08:00
chai2010 3600022287 规范 func 关键字使用 2023-04-13 19:12:01 +08:00
chai2010 268ca928e2 规范注释 2023-04-13 19:10:04 +08:00
chai2010 2cf421d628 更新 changelog, 准备 v0.6.0 变更日志 2023-04-13 17:59:05 +08:00
衍星居士 518175a355
!10 添加了中文的打印素数示例
Merge pull request !10 from 衍星居士/frontend_wz
2023-04-13 06:14:00 +00:00
衍星居士 ee40dc46f2 添加打印素数的中文示例 2023-04-13 06:12:31 +00:00
衍星居士 b7c773c4b7
!9 修改中文示例代码的缩进
Merge pull request !9 from 衍星居士/frontend_wz
2023-04-13 01:55:54 +00:00
衍星居士 e893d750e8 修改中文代码的缩进 2023-04-13 09:54:24 +08:00
chai2010 5bfe0e8538
!8 将中文示例组织为工程形式,并添加了BrainFuck的示例
Merge pull request !8 from 衍星居士/frontend_wz
2023-04-13 01:44:44 +00:00
3dgen d9be646bc3 Merge branch 'backend_wasm' 2023-04-13 09:38:22 +08:00
3dgen ad62b475f6 增加具名interface例子 2023-04-13 09:37:26 +08:00
衍星居士 213f3fb84b 添加了中文内置函数”长“和内置类型”字“ 2023-04-13 09:32:22 +08:00
衍星居士 f54bfd8b7d Merge branch 'frontend_wz' of gitee.com:wa-lang/wa into frontend_wz 2023-04-13 08:33:49 +08:00
visus 1eab7f15ac 【凹中文】基本完成了烧脑虚拟机的示例 2023-04-13 00:33:32 +00:00
visus b5298241e6 [凹中文]完善了循环,修改了示例结构 2023-04-13 00:33:32 +00:00
chai2010 ad68ca2a1a Merge commit 'd6d7b56d745f30d29542575c0408aeb775647823' 2023-04-12 22:20:44 +08:00
3dgen d6d7b56d74 修正全局变量类型未处理的问题 2023-04-12 09:59:56 +08:00
chai2010 f27cb5be71 临时屏蔽 Windows 环境变量异常问题 2023-04-11 23:36:28 +08:00
3dgen da295b11db 解决合并冲突 2023-04-11 12:33:30 +08:00
3dgen 9dc08a7346 interface 阶段性实现 2023-04-11 11:45:33 +08:00
chai2010 7b0be4eccf 零碎细节修改 2023-04-11 06:47:30 +08:00
chai2010 cda137fcb9 删除 testing 包, 更新 changelog 文件 2023-04-09 15:40:05 +08:00
chai2010 22b537a139 assert 支持输出位置信息 2023-04-09 15:39:20 +08:00
chai2010 2ee362670a 完善 assert 内置测试函数支持 2023-04-04 19:18:32 +08:00
visus cfd16e12b7 【凹中文】基本完成了烧脑虚拟机的示例 2023-04-04 15:41:36 +08:00
chai2010 894cc5178e assert 语义调整为 testing 环境的运行时函数 2023-04-04 01:47:13 +08:00
visus 4c46c6a908 Merge branch 'frontend_wz' of gitee.com:wa-lang/wa into frontend_wz 2023-04-03 23:34:46 +08:00
visus 7cacbc9ff5 [凹中文]完善了循环,修改了示例结构 2023-04-03 15:34:26 +00:00
visus aa5a73e83b [凹中文]完善了循环,修改了示例结构 2023-04-03 23:33:43 +08:00
chai2010 d3b0bd33bf 更新 readme 2023-04-03 21:13:58 +08:00
chai2010 5319f20623 main 函数移到 wacli 包中 2023-04-03 20:29:30 +08:00
chai2010 dd2f0fe31e wat 后端汇编代码拆分到相关 wa 包中 2023-04-03 20:24:39 +08:00
chai2010 1b663af678 loader 包增加对汇编代码的解析 2023-04-03 00:00:00 +08:00
chai2010 3bce782a22 Revert "升级 wazero-1.0.1, 感谢 @codefromthecrypt 的补丁"
This reverts commit fa5f7bb98f.
2023-04-02 06:50:03 +08:00
chai2010 325bb9348b 清理局部垃圾代码 2023-04-01 14:44:29 +08:00
chai2010 4b946c5b28 wat 后端增加包汇编代码输出 2023-04-01 14:37:16 +08:00
chai2010 fa5f7bb98f 升级 wazero-1.0.1, 感谢 @codefromthecrypt 的补丁
https://github.com/wa-lang/wa/pull/44#issuecomment-1491343042
2023-03-31 23:31:19 +08:00
chai2010 0b8bf8c6fe loader.Package 结构增加汇编代码文件 2023-03-30 06:49:28 +08:00
chai2010 6e08243d8f 规范 后端/OS/ARCH 常量定义 2023-03-30 06:39:43 +08:00
chai2010 9cc2fd9dba 增加部分 math 函数 2023-03-25 23:20:56 +08:00
chai2010 cf28bd3ab4 更新 readme 2023-03-25 21:03:52 +08:00
chai2010 d8c932c392 配置 homebrew-tap 2023-03-25 07:43:57 +08:00
chai2010 57fdc34cf4 v0.5.1 更新 changelog 2023-03-25 06:46:36 +08:00
chai2010 ebd2e61d83 完善 release action 2023-03-25 06:31:05 +08:00
chai2010 179bcbe7fb 添加 github release action 2023-03-25 06:21:22 +08:00
chai2010 6a13e3fb04 完善零参数函数格式化 2023-03-24 21:07:52 +08:00
xxx 8f07450308 fix: wat error 2023-03-23 17:39:54 +08:00
chai2010 b29e641ce7 snake: 补充缺少的 wasi 方法 2023-03-21 23:35:23 +08:00
chai2010 11a95a5b56 syscall/wasi: 补齐全部的 API 函数 2023-03-19 19:42:53 +08:00
chai2010 c7c1b3248f wasi: 导入fs函数 2023-03-19 11:34:00 +08:00
chai2010 83585ee274 补充 wasi 函数 2023-03-19 08:01:58 +08:00
chai2010 0667479489 wasi 函数移入 syscall/wasi 包 2023-03-18 23:43:16 +08:00
chai2010 a22c8760da 更新 changelog 2023-03-18 15:48:19 +08:00
chai2010 37830f7afd 增加 os.Environ 函数 2023-03-18 15:39:45 +08:00
chai2010 11ec6901a8 初步支持单元测试 2023-03-18 07:07:12 +08:00
chai2010 322a94b481 增加 testing 包 2023-03-16 06:30:19 +08:00
chai2010 2aa2853190 单元测试模式准备工作, 解析测试代码 2023-03-15 23:52:27 +08:00
chai2010 9f498e0bb1 main 强制导入 runtime 包 2023-03-14 23:41:00 +08:00
chai2010 7f2f0983df 增加 os.Exit 函数 2023-03-12 23:11:32 +08:00
chai2010 e916cb0a13 api: RunCode 增加 args 参数 2023-03-12 22:59:52 +08:00
chai2010 c261f1d7a8 更新 readme 2023-03-12 07:47:40 +08:00
chai2010 f96ea1baa7 更新 changelog 2023-03-12 07:41:29 +08:00
chai2010 5b1beef9d9 凹禁止 package 语法, 仅作为一个保留关键字 2023-03-12 07:38:59 +08:00
chai2010 fff4d8c990 增加 lsp 包, 定义基本类型 2023-03-12 07:24:26 +08:00
chai2010 339140a92f 支持 os.Args 2023-03-11 07:36:22 +08:00
chai2010 14a24b2c6c 调整 ref2ptr 例子 2023-03-10 06:37:52 +08:00
3dgen bdea01b73b Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-03-09 15:06:15 +08:00
3dgen 6019f6de47 临时增加*T => ptr 2023-03-09 14:59:57 +08:00
chai2010 6e49656d7b snake: 补充缺少的 wasi 导入函数 2023-03-08 23:16:52 +08:00
chai2010 b2066f215d wasi: 导入 args 相关函数 2023-03-08 23:11:13 +08:00
chai2010 4b2c0de46e tag v0.5.0 2023-03-06 07:29:26 +08:00
chai2010 d2ec79f793 更新变更日志 2023-03-05 23:33:53 +08:00
chai2010 4c21088373 Merge branch 'dev' 2023-03-05 23:29:38 +08:00
chai2010 fc0a68ee51 支持 wasi 规范 2023-03-05 23:27:21 +08:00
chai2010 c4f7d33bc0 internal/app: 重构代码, 拆分为多个文件 2023-03-04 10:40:10 +08:00
chai2010 e1455ef7c2 更新 readme 2023-03-04 06:33:17 +08:00
chai2010 d8dab70ded 支持 build tags 构建 2023-03-04 06:13:35 +08:00
chai2010 6fb188c200 增加 buildtag 包 2023-03-02 22:35:24 +08:00
chai2010 f2ba3dfa45 命令行增加 test 子命令行入口, 还未实现 2023-03-02 22:23:28 +08:00
chai2010 cba0b0ccf8 yacc: expr 例子增加 readme 2023-02-20 23:07:57 +08:00
chai2010 b670f33816 yacc: 调整生成的方法代码风格 2023-02-19 23:22:52 +08:00
chai2010 c5035ebd93 yacc: expr 例子完善, 包含生成的代码 2023-02-19 23:15:29 +08:00
chai2010 4b725e0a0c yacc: expr 例子更新, 增加小括号 2023-02-19 23:08:55 +08:00
chai2010 b4240ed841 yacc: 去掉 copy, expr 生成的 wa 代码可执行 2023-02-19 23:03:57 +08:00
3dgen 64315c0827 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-02-19 22:48:10 +08:00
3dgen 0b1d0e90e4 增加 buildin.cap 2023-02-19 22:47:38 +08:00
3dgen 5401d8e8e0 zz 2023-02-19 22:47:12 +08:00
3dgen 7f536c42c0 支持 ssa.Index 2023-02-19 22:23:54 +08:00
3dgen 6b2266b261 增加 string 的 = 和 != 函数 2023-02-19 20:26:33 +08:00
3dgen ea73f5089a 增加xor指令 2023-02-19 20:25:41 +08:00
chai2010 87b79eae3f yacc: 暂时避免用匿名结构体 2023-02-19 10:35:54 +08:00
chai2010 4ad1ca8ab7 yacc: 命令行参数加引号, 以适配Windows环境 2023-02-19 10:11:33 +08:00
chai2010 57c5aedfed yacc: 输出 wa 时, 忽略 package 语句 2023-02-18 21:26:08 +08:00
chai2010 6c2175e228 yacc: 输出代码符合 wa 语法 2023-02-18 21:16:05 +08:00
chai2010 0475f5c478 yacc: 继续简化代码, 消除部分 goto, 去掉 fmt 格式化依赖, 去掉 defer 依赖 2023-02-18 20:43:11 +08:00
chai2010 5840bb11b1 标准库: 实现 strconv.Itoa 函数 2023-02-18 20:16:03 +08:00
chai2010 81e9f84c35 yacc: 增加 expr 例子 2023-02-17 22:33:31 +08:00
chai2010 982f931408 Merge branch 'dev-yacc' 2023-02-17 09:04:13 +08:00
chai2010 4c0404151a yacc 支持准备工作 2023-02-17 09:03:31 +08:00
3dgen 29e0f8a4b2 interface 支持的准备工作(第一阶段) 2023-02-16 19:40:41 +08:00
3dgen bba7948427 zz 2023-02-06 16:28:35 +08:00
chai2010 c8fd5cab43 更新 readme, 淘汰 fn 关键字 2023-02-04 16:48:38 +08:00
chai2010 852341fe17 更新 readme 中 playground 截图 2023-02-04 16:42:41 +08:00
chai2010 f619bd4ba1 playground: 增加错误返回 2023-02-04 16:16:11 +08:00
chai2010 c1f4a48aaf gitee 流水线完善 2023-02-04 15:55:02 +08:00
chai2010 3c612d5e07 gitee 流水线完善 2023-02-04 15:51:21 +08:00
chai2010 f65034ff99 gitee 流水线完善 2023-02-04 15:34:33 +08:00
chai2010 1a2ad353f7 gitee 流水线增加 goproxy 2023-02-04 15:27:17 +08:00
chai2010 5a7e75d007 继续更新 gitee 流水线 2023-02-04 12:11:05 +08:00
chai2010 8185072864 gitee 流水线只构建 64 位目标 2023-02-04 12:01:54 +08:00
chai2010 e73e354858 更新 gitee 流水线 Go 版本 2023-02-04 11:51:48 +08:00
chai2010 65933f3cd6
add default pipeline template yaml 2023-02-04 03:27:20 +00:00
chai2010 3bf4a9d21e
!7 说明所需 Go 版本
Merge pull request !7 from 吴烜/go版本需求
2023-02-04 03:11:43 +00:00
chai2010 4aa65696bb 完善命令行错误信息处理 2023-02-03 23:52:14 +08:00
chai2010 150da4c427 Github 不接受 PR 2023-02-02 21:55:44 +08:00
吴烜 d77ac2235d 说明所需 Go 版本 2023-02-01 10:07:43 -08:00
chai2010 d5b03afcda 英文前端删除中文关键字支持, 中文编程采用独立的前端语法 2023-01-31 23:23:11 +08:00
chai2010 2ff42af7a6 调整注释合规, 中文别名关键字后面空格可省 2023-01-26 22:16:11 +08:00
chai2010 44a9f9c451
Update README.md 2023-01-25 21:26:31 +08:00
chai2010 b3ded47b9a 更新 readme 2023-01-10 08:32:43 +08:00
chai2010 9cd760a40e 更新 readme 2023-01-09 23:54:08 +08:00
3dgen 5910bae2c0 zz 2023-01-09 18:12:24 +08:00
chai2010 e0fab5a873 5号提案: fn 改成 func, 保持和 wasm 对齐 2023-01-08 22:16:35 +08:00
chai2010 b13815ad6a 更新 v0.4.1 日志 2023-01-08 15:21:45 +08:00
chai2010 e4fab86f0f snake 增加英文 readme 2023-01-07 16:30:04 +08:00
chai2010 ab7b28110d 更新 readme 2023-01-07 12:27:15 +08:00
chai2010 dc4eb531a8 更新 readme 2023-01-07 11:40:36 +08:00
chai2010 91d333fd11 更新 readme 2023-01-04 22:39:38 +08:00
xxx 9dc49f59d7 feat: optimized style 2023-01-03 20:33:49 +08:00
xxx cda5f6d1aa docs: up 2023-01-03 12:57:01 +08:00
3dgen b4cda968e3 zz 2023-01-03 09:49:01 +08:00
3dgen b4075787f5 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-01-03 09:48:18 +08:00
3dgen ddb960923b zz 2023-01-03 09:24:38 +08:00
chai2010 a987a0da45 Merge branch 'master-github' 2023-01-03 08:28:02 +08:00
xxx 04daf2f2dc chore: up snake demo 2023-01-03 00:00:05 +08:00
xxx b3f8d30991
!6 feat: optimized ui and mobile operations
merge
2023-01-02 15:45:09 +00:00
xxx 403a5187d8 style: add btns 2023-01-02 23:44:05 +08:00
xxx 9968b7b493 docs: up readme 2023-01-02 23:23:17 +08:00
xxx 88eda0e09d feat: optimized ui and mobile operations 2023-01-02 23:16:21 +08:00
xxx b582673553 chore: del useless code 2023-01-02 23:13:28 +08:00
chai2010 68a1c6a6e8 更新 hello 例子工程 2023-01-01 20:13:10 +08:00
chai2010 74c0da97a1 增加 any 作为预定义类型 2023-01-01 06:50:33 +08:00
chai2010 9cd8b943e0
!5 功能:添加基本的凹中文语法支持
Merge pull request !5 from 衍星居士/frontend_wz
2022-12-27 13:03:40 +00:00
衍星居士 b07b73b0b9 添加了凹中文的初步支持,本次提交的6个示例文件都可以运行 2022-12-27 10:32:29 +08:00
衍星居士 332c0dc093 添加凹中文前端的基本说明 2022-12-26 11:49:05 +08:00
chai2010 dde92fc69e 更新贪吃蛇 readme 2022-12-24 08:56:25 +08:00
chai2010 2b6a8ac1af 格式化 snake 例子 2022-12-24 08:44:04 +08:00
chai2010 6818c41079 更新 action 2022-12-21 22:39:37 +08:00
chai2010 81104df993 publish action 增加 snake 2022-12-21 22:35:16 +08:00
3dgen 6b8bdca579 Add example:snake/compile.md 2022-12-21 21:26:24 +08:00
3dgen 196c51d953 Update example:snake 2022-12-21 21:21:21 +08:00
3dgen c68ecc5aad 更新首页说明 2022-12-21 21:20:39 +08:00
3dgen d0f0faf300 Change type of globals from `Pointer` to `Ref` 2022-12-21 21:19:45 +08:00
3dgen d78f1a2037 Add zero-initializing while call waHeapAlloc 2022-12-21 21:17:35 +08:00
3dgen 42fc2f09bd Merge branch 'master' of https://gitee.com/wa-lang/wa 2022-12-21 11:55:02 +08:00
3dgen ff61f00a3c 修改CLA流程 2022-12-21 11:54:57 +08:00
丁尔男 df99c24814
!3 [fix] 中文 README <div> 没有关闭,导致代码格式居中对齐
Merge pull request !3 from wanglong001/master
2022-12-21 03:44:31 +00:00
3dgen cd172cae65 Update example:snake 2022-12-19 22:04:28 +08:00
3dgen 374106e4d1 Update example:snake 2022-12-19 21:45:35 +08:00
3dgen 727730ad82 Fix a bug in function-value generating 2022-12-19 21:45:15 +08:00
3dgen cdce69bb5c Change `Module.findFunc` to `Module.FindFunc` 2022-12-19 21:38:02 +08:00
3dgen 038dfca730 Update example:snake 2022-12-19 21:36:39 +08:00
3dgen 2bf95b1062 Update package:canvas 2022-12-18 21:25:01 +08:00
chai2010 3adbadda0b 格式化 malloc 代码并启用 2022-12-18 12:31:56 +08:00
3dgen 2f66ebb24e update runtime.heap 2022-12-18 12:19:09 +08:00
chai2010 871b2a6474 完善 malloc 代码 2022-12-18 10:38:06 +08:00
chai2010 30fc86a8a9 清理 malloc 无关代码 2022-12-17 21:33:01 +08:00
chai2010 02cd2861ad 实现 K&R 版本的 malloc 2022-12-17 20:48:09 +08:00
3dgen e28dd9c68a Init package: canvas 2022-12-15 20:17:54 +08:00
3dgen d327540f15 Support ssa.MakeSlice 2022-12-15 19:14:10 +08:00
3dgen 6fc0271286 Update example: snake 2022-12-14 22:32:45 +08:00
xxx 02102c0ea0 !4 feat: add canvas js code
* feat: add js code
2022-12-14 02:27:40 +00:00
3dgen 82c2de4156 Merge branch 'master' of https://gitee.com/wa-lang/wa 2022-12-12 20:12:07 +08:00
3dgen c236bb1346 Add example: snake 2022-12-12 20:11:52 +08:00
3dgen 6500b8bafb Support param names with non-ANSI characters 2022-12-12 19:37:52 +08:00
wanglong001 e3461e7333 [fix] README-zh.md div 没有关闭 2022-12-12 16:39:33 +08:00
chai2010 e8ca998fda
更新 readme
Signed-off-by: chai2010 <chaishushan@gmail.com>
2022-12-07 13:33:19 +00:00
3dgen 37c92017bf Merge branch 'master' of https://gitee.com/wa-lang/wa 2022-12-06 22:19:28 +08:00
3dgen e7add74c7c wat后端支持#wa:export标签 2022-12-06 22:19:15 +08:00
chai2010 084868cd89 更新错别字,更新英文 readme 2022-12-04 17:05:18 +08:00
chai2010 aea9764911 更新 readme 2022-12-03 15:10:28 +08:00
chai2010 e30c333882 Merge branch 'master' of github.com:wa-lang/wa 2022-12-03 14:53:49 +08:00
chai2010 941b366d4d 更新日志 2022-12-03 14:53:16 +08:00
Crypt Keeper e99bc9d428
deps: updates wazero to 1.0.0-pre.4 (#41)
This updates [wazero](https://wazero.io/) to [1.0.0-pre.4](https://github.com/tetratelabs/wazero/releases/tag/v1.0.0-pre.4).

Notably, v1.0.0-pre.4:
* improves module initialization speed
* supports listeners in the compiler engine
* supports WASI `fd_pread`, `fd_readdir` and `path_filestat_get`
* breaks GoModuleFunc API

Signed-off-by: Adrian Cole <adrian@tetrate.io>

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-12-03 14:52:09 +08:00
3dgen 354b7c79ed Merge branch 'master' of https://gitee.com/wa-lang/wa 2022-11-30 23:03:06 +08:00
3dgen 21ce68b718 删除废弃代码 2022-11-30 23:02:57 +08:00
chai2010 3f5d410c87 更新 arduino 打印的提示信息 2022-11-30 22:03:20 +08:00
chai2010 e954d811d2 Merge branch 'master' of gitee.com:wa-lang/wa 2022-11-30 21:51:33 +08:00
chai2010 3e1ba7bee5 arduino 添加 wa 例子, 可在 nano 33 开发板执行 2022-11-30 21:51:00 +08:00
3dgen bcf5bd84bb Merge branch 'master' of https://gitee.com/wa-lang/wa 2022-11-30 20:36:36 +08:00
3dgen ea0eca188c 修正常量字符串中换行符不能正常保存的问题 2022-11-30 20:36:24 +08:00
chai2010 f72d55a6dd arduino 添加 wat 例子 2022-11-30 06:39:04 +08:00
chai2010 dd3b859602 更新 readme 2022-11-30 06:20:29 +08:00
chai2010 f91dc91ca2 run 支持 wat 和 wasm 文件 2022-11-30 05:49:51 +08:00
chai2010 efa04f0122
!1 feat:调整代码和导入 fmt 函数
Merge pull request !1 from xxx/master
2022-11-29 21:29:29 +00:00
xxx b3d7cacfb7 fix:return code 2022-11-29 23:34:16 +08:00
xxx f6a14f39be feat:adjust code and export fmt 2022-11-29 23:26:11 +08:00
chai2010 9558eaea3f 合并分支 2022-11-29 21:48:38 +08:00
chai2010 5acae3a5a1 更新主仓库地址 2022-11-29 21:47:55 +08:00
3dgen 11670ae427 修正匿名包含非英文结构体错误 2022-11-29 21:12:37 +08:00
3dgen e56e1d5e6c 优化函数命名 2022-11-29 21:11:58 +08:00
3dgen 5a3247afdf 优化结构体命名 2022-11-29 21:11:37 +08:00
3dgen 4fb0c935f1 部分修正非英文函数名和全局变量无法编译的错误 2022-11-29 20:51:41 +08:00
chai2010 fbc63be3ac 修复 test 2022-11-29 06:57:24 +08:00
chai2010 0ecb774078 更新导入路径 2022-11-29 06:49:55 +08:00
chai2010 0c13a9c25e 调整包路径为 wa-lang.org/wa 2022-11-28 23:12:58 +08:00
chai2010 b0ce767555 配置 go-get 元信息 2022-11-28 22:49:22 +08:00
chai2010 0dcb11875c 合并分支 2022-11-28 22:47:19 +08:00
3dgen 73334e4008 更新license 2022-11-28 19:22:02 +08:00
3dgen 82a1abf22e Merge branch 'master' of https://gitee.com/wa-lang/wa 2022-11-28 19:02:14 +08:00
Ben Shi d80d88bc0f llvm: implement support of closure functions. 2022-11-28 11:13:37 +08:00
chai2010 7da144fad5 完善 arduino 本地打印格式 2022-11-27 15:53:09 +08:00
chai2010 0e42f3282b Merge branch 'master' of gitee.com:wa-lang/wa 2022-11-27 15:47:43 +08:00
chai2010 a89e8072dd 本地增加 arduino 模拟执行 2022-11-27 15:45:13 +08:00
3dgen 3c4a4c96a0 Merge branch 'master' of https://gitee.com/wa-lang/wa 2022-11-27 09:31:57 +08:00
3dgen 0cf5080d31 优化Array结构 2022-11-27 00:06:56 +08:00
Ben Shi cb393db095 llvm: implement support of internal anonymous functions. 2022-11-26 16:50:08 +08:00
Ben Shi 42a5c40720 llvm: fix broken native build mode. 2022-11-26 15:20:31 +08:00
chai2010 5589c5013e Merge branch 'master' of github.com:wa-lang/wa 2022-11-26 13:24:10 +08:00
chai2010 09bcc896ca 添加 wasm-arduino 例子 2022-11-26 13:22:43 +08:00
3dgen 071c2102e1 优化Tuple结构 2022-11-26 12:30:55 +08:00
3dgen 5aa6e7ba76 优化String结构
优化Slice结构
2022-11-26 12:26:27 +08:00
3dgen b694219b88 优化slice结构 2022-11-26 12:22:02 +08:00
3dgen fa307e06c1 Merge branch 'master' of https://github.com/wa-lang/wa 2022-11-26 12:11:20 +08:00
3dgen 3631ef07c7 修正匿名非闭包函数未生成
支持const
2022-11-26 12:10:47 +08:00
chai2010 e6a41eaf42 更新 readme 2022-11-26 10:00:35 +08:00
chai2010 d00031e8e3 更新中文 readme 2022-11-26 09:59:06 +08:00
chai2010 849e0ab55b wasm 运行时环境移动到独立包 2022-11-26 09:52:50 +08:00
chai2010 e4aa9a902d 更新 changelog 2022-11-26 08:48:44 +08:00
chai2010 7ffffcd25d 更新 changelog 2022-11-26 08:47:46 +08:00
chai2010 d6a44a7b1f 局部代码调整 2022-11-26 08:45:02 +08:00
chai2010 312838ada3 支持多平台区分源文件 2022-11-26 08:29:05 +08:00
3dgen c4a210a3ed 增加闭包例子 2022-11-25 21:29:42 +08:00
3dgen 3da98a3a6a 删除无用例子 2022-11-25 20:03:29 +08:00
3dgen 7ad7384830 Merge branch 'master' of https://github.com/wa-lang/wa 2022-11-25 16:54:39 +08:00
3dgen ee381daf76 Merge branch 'master' of https://github.com/wa-lang/wa 2022-11-24 21:04:23 +08:00
3dgen 7939090815 支持函数值 2022-11-24 21:04:08 +08:00
Ben Shi d33639ac6d Format several .wa files. 2022-11-24 19:19:38 +08:00
chai2010 e7ad43e898 更新错别字 2022-11-24 08:23:00 +08:00
Ben Shi e9df3881f7 llvm: implement translation of bitwise logic and shift operations. 2022-11-23 15:52:50 +08:00
Ben Shi 74a1e417da llvm: support building WA source file to an Arduino project 2022-11-23 11:20:46 +08:00
chai2010 9ea8f4643c 更新 readme 2022-11-23 09:23:39 +08:00
chai2010 06674b2cef 添加中文 readme 2022-11-23 09:21:59 +08:00
chai2010 b57b736a1a 更新play 2022-11-22 20:27:31 +08:00
chai2010 a4578ccff8 调整参数处理代码 2022-11-22 20:23:41 +08:00
3dgen 2efe964072 Merge branch 'master' of https://github.com/wa-lang/wa 2022-11-21 21:07:42 +08:00
3dgen c1a38b4285 waPrint系列函数重定向至runtime包 2022-11-21 21:07:34 +08:00
chai2010 8e6684c1f4 syscall 调整 2022-11-20 22:07:19 +08:00
3dgen 616319ff99 imports内置 2022-11-20 13:22:23 +08:00
chai2010 7d0e503e7e 更新 readme 2022-11-20 07:48:21 +08:00
chai2010 2232afb8f5 fmt wa code 2022-11-20 07:45:22 +08:00
chai2010 c7dcca1479 完善 config 参数 2022-11-20 07:29:19 +08:00
chai2010 485f2d713e 完善 example 2022-11-20 07:03:01 +08:00
chai2010 c4537beefe 完善 example 2022-11-20 07:01:42 +08:00
chai2010 ef33d595c7 完善注释标志 2022-11-20 06:53:05 +08:00
chai2010 b76e516345 完善 example 2022-11-20 06:46:55 +08:00
chai2010 c4e4e24d29 更新 waroot 2022-11-19 23:04:42 +08:00
chai2010 480b21705e 更新 changelog 2022-11-19 05:39:52 +08:00
chai2010 2390c86f34 完善 BrainFuck 例子 2022-11-19 05:32:13 +08:00
chai2010 7282626f67 完善方法格式化 2022-11-19 05:28:13 +08:00
chai2010 bb7a98be8e 方法 this 为指针类型 2022-11-19 05:19:58 +08:00
chai2010 c538bdb43c 改进方法语法 2022-11-19 00:08:32 +08:00
Ben Shi 99e7cb3372 llvm: support functions with multiple return values. 2022-11-18 20:43:17 +08:00
chai2010 3b703f0373 屏蔽调试代码 2022-11-17 22:42:23 +08:00
chai2010 f7d81a5c6d 调整 bf 代码 2022-11-17 22:15:50 +08:00
3dgen 62b1598034 修正8/16位整数存储错误 2022-11-17 21:43:18 +08:00
3dgen 9951814dd3 Merge branch 'master' of https://github.com/wa-lang/wa 2022-11-17 20:51:24 +08:00
3dgen d84889e886 增加取字符串元素 2022-11-17 20:49:21 +08:00
chai2010 18fc7c491d 修复结构体成员格式化 2022-11-16 23:57:10 +08:00
chai2010 b7f5364277 添加 brainfuck.wa 例子 2022-11-16 23:41:16 +08:00
chai2010 b21620cde6 Merge branch 'master' of github.com:wa-lang/wa 2022-11-16 08:56:49 +08:00
chai2010 bc3b0caf00 更新 changgelog 2022-11-16 08:54:41 +08:00
3dgen 292c8d5301 Merge branch 'master' of https://github.com/wa-lang/wa 2022-11-16 08:17:16 +08:00
3dgen c42f68c44e 支持多返回值 2022-11-15 22:27:52 +08:00
712 changed files with 71822 additions and 8702 deletions

17
.github/workflows/pr.yml vendored Normal file
View File

@ -0,0 +1,17 @@
# 版权 @2022 凹语言 作者。保留所有权利。
name: Close PRs
on:
pull_request_target:
types: [opened]
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: superbrothers/close-pull-request@v3
with:
# Optional. Post a issue comment just before closing a pull request.
comment: "这里是镜像仓库, 不接受 PR, 请移步 https://gitee.com/wa-lang"

36
.github/workflows/publish.yml vendored Normal file
View File

@ -0,0 +1,36 @@
name: Deploy
on:
push:
branches:
- master
pull_request:
branches:
- master
types:
- closed
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17
- run: make -C internal/app/wawasm
- run: make -C waroot/examples/snake publish
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
personal_token: ${{ secrets.WA_DEPLOY }}
publish_dir: docs
publish_branch: gh-pages
force_orphan: true
user_name: "github-actions[bot]"
user_email: "github-actions[bot]@users.noreply.github.com"

45
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,45 @@
# https://github.com/goreleaser/goreleaser-action
name: Release
on:
push:
tags:
- "v*"
permissions:
contents: write
jobs:
Test:
runs-on: ubuntu-latest
if: ${{github.repository == 'wa-lang/wa'}}
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17
- run: make ci-test-all
Publish:
runs-on: ubuntu-latest
if: ${{github.repository == 'wa-lang/wa'}}
needs: [Test]
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v4
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.WA_DEPLOY }}

View File

@ -23,14 +23,16 @@ jobs:
- run: go version
- run: go env
- run: make ci-test-all
- run: go test -v -coverprofile=profile.cov ./...
- run: go install
- run: wa -h
- run: wa hello.wa
- run: wa run _examples/prime
- run: wa run hello.wa
- run: cd waroot && wa run examples/prime
- run: cd waroot && wa run hello.wa
- run: cd waroot && wa run -target=chrome hello.wa
- uses: shogo82148/actions-goveralls@v1
with:
@ -50,14 +52,16 @@ jobs:
- run: go version
- run: go env
- run: make ci-test-all
- run: go test -v ./...
- run: go install
- run: wa -h
- run: wa hello.wa
- run: wa run _examples/prime
- run: wa run hello.wa
- run: cd waroot && wa run examples/prime
- run: cd waroot && wa run hello.wa
- run: cd waroot && wa run -target=chrome hello.wa
build-and-test-macos:
runs-on: macos-12
@ -73,11 +77,13 @@ jobs:
- run: go version
- run: go env
- run: make ci-test-all
- run: go test -v ./...
- run: go install
- run: wa -h
- run: wa hello.wa
- run: wa run _examples/prime
- run: wa run hello.wa
- run: cd waroot && wa run examples/prime
- run: cd waroot && wa run hello.wa
- run: cd waroot && wa run -target=chrome hello.wa

7
.gitignore vendored
View File

@ -1,5 +1,7 @@
/.fleet
/.vscode
/_build*
/hello
wa
wa.exe
@ -14,5 +16,10 @@ wat2wasm.exe
*.ll
*.s
*.out*
*.wasm
*.wasm.*
y.wa.*
/docs/snake/*
_target

86
.goreleaser.yml Normal file
View File

@ -0,0 +1,86 @@
# This is an example .goreleaser.yml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
before:
hooks:
- go version
builds:
- id: default
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
# 使用 ldflags="-s -w" 去掉符号表和调试信息,以减少发布包的大小
ldflags:
- -s
- -w
ignore:
- goos: linux
goarch: arm64
- goos: windows
goarch: arm64
main: .
archives:
- id: default
builds:
- default
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
format_overrides:
- goos: windows
format: zip
checksum:
name_template: 'checksums.txt'
changelog:
use: github
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
release:
github:
owner: wa-lang
name: wa
draft: false
footer: |
Homepage https://wa-lang.org
brews:
- tap:
owner: wa-lang
name: homebrew-tap
url_template: "https://github.com/wa-lang/wa/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
download_strategy: CurlDownloadStrategy
# Git author used to commit to the repository.
# Defaults are shown.
commit_author:
name: GoReleaser Bot
email: goreleaser@carlosbecker.com
folder: HomebrewFormula
homepage: "https://github.com/wa-lang/wa"
description: "The Wa Programming Language"
license: "AGPL-3.0 license"
skip_upload: false
test: |
system "#{bin}/wa"
scoop:
url_template: "https://github.com/wa-lang/wa/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
bucket:
owner: wa-lang
name: scoop-bucket
branch: master
token: "{{ .Env.GITHUB_TOKEN }}"
folder: Scoops
commit_author:
name: goreleaserbot
email: bot@goreleaser.com
commit_msg_template: "Scoop update for {{ .ProjectName }} version {{ .Tag }}"
homepage: "http://github.com/wa-lang/wa"
description: "The Wa Programming Language"
license: AGPL-3.0 license

View File

@ -0,0 +1,70 @@
version: '1.0'
name: branch-pipeline
displayName: BranchPipeline
stages:
- stage:
name: compile
displayName: 编译
steps:
- step: build@golang
name: build_golang
displayName: Golang 构建
# 支持1.8、1.10、1.11、1.12、1.13、1.14、1.15、1.16八个版本
golangVersion: 1.17
# 构建命令
commands: |
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
go test -v ./...
mkdir -p output/wa-lang-darwin
mkdir -p output/wa-lang-linux64
mkdir -p output/wa-lang-win64
GOOS=darwin GOARCH=amd64 go build -o output/wa-lang-darwin/wa main.go
GOOS=linux GOARCH=amd64 go build -o output/wa-lang-linux64/wa main.go
GOOS=windows GOARCH=amd64 go build -o output/wa-lang-win64/wa.exe main.go
chmod +X output/wa-lang-linux64/wa
./output/wa-lang-linux64/wa
./output/wa-lang-linux64/wa -h
#./output/wa-lang-linux64/wa waroot/hello.wa
#./output/wa-lang-linux64/wa run waroot/examples/prime
#./output/wa-lang-linux64/wa run waroot/hello.wa
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中7天后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:
- ./output
- step: publish@general_artifacts
name: publish_general_artifacts
displayName: 上传制品
# 上游构建任务定义的产物名默认BUILD_ARTIFACT
dependArtifact: BUILD_ARTIFACT
# 上传到制品库时的制品命名默认output
artifactName: output
dependsOn: build_golang
- stage:
name: release
displayName: 发布
steps:
- step: publish@release_artifacts
name: publish_release_artifacts
displayName: '发布'
# 上游上传制品任务的产出
dependArtifact: output
# 发布制品版本号
version: '1.0.0.0'
# 是否开启版本号自增,默认开启
autoIncrement: true
triggers:
push:
branches:
exclude:
- master
include:
- .*

View File

@ -0,0 +1,68 @@
version: '1.0'
name: master-pipeline
displayName: MasterPipeline
stages:
- stage:
name: compile
displayName: 编译
steps:
- step: build@golang
name: build_golang
displayName: Golang 构建
# 支持1.8、1.10、1.11、1.12、1.13、1.14、1.15、1.16八个版本
golangVersion: 1.17
# 构建命令
commands: |
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,
go test -v ./...
mkdir -p output/wa-lang-darwin
mkdir -p output/wa-lang-linux64
mkdir -p output/wa-lang-win64
GOOS=darwin GOARCH=amd64 go build -o output/wa-lang-darwin/wa main.go
GOOS=linux GOARCH=amd64 go build -o output/wa-lang-linux64/wa main.go
GOOS=windows GOARCH=amd64 go build -o output/wa-lang-win64/wa.exe main.go
chmod +X output/wa-lang-linux64/wa
./output/wa-lang-linux64/wa
./output/wa-lang-linux64/wa -h
#./output/wa-lang-linux64/wa waroot/hello.wa
#./output/wa-lang-linux64/wa run waroot/examples/prime
#./output/wa-lang-linux64/wa run waroot/hello.wa
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中24小时后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:
- ./output
- step: publish@general_artifacts
name: publish_general_artifacts
displayName: 上传制品
# 上游构建任务定义的产物名默认BUILD_ARTIFACT
dependArtifact: BUILD_ARTIFACT
# 上传到制品库时的制品命名默认output
artifactName: output
dependsOn: build_golang
- stage:
name: release
displayName: 发布
steps:
- step: publish@release_artifacts
name: publish_release_artifacts
displayName: '发布'
# 上游上传制品任务的产出
dependArtifact: output
# 发布制品版本号
version: '1.0.0.0'
# 是否开启版本号自增,默认开启
autoIncrement: true
triggers:
push:
branches:
include:
- master

55
.workflow/pr-pipeline.yml Normal file
View File

@ -0,0 +1,55 @@
version: '1.0'
name: pr-pipeline
displayName: PRPipeline
stages:
- stage:
name: compile
displayName: 编译
steps:
- step: build@golang
name: build_golang
displayName: Golang 构建
# 支持1.8、1.10、1.11、1.12、1.13、1.14、1.15、1.16八个版本
golangVersion: 1.17
# 构建命令
commands: |
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,
go test -v ./...
mkdir -p output/wa-lang-darwin
mkdir -p output/wa-lang-linux64
mkdir -p output/wa-lang-win64
GOOS=darwin GOARCH=amd64 go build -o output/wa-lang-darwin/wa main.go
GOOS=linux GOARCH=amd64 go build -o output/wa-lang-linux64/wa main.go
GOOS=windows GOARCH=amd64 go build -o output/wa-lang-win64/wa.exe main.go
chmod +X output/wa-lang-linux64/wa
./output/wa-lang-linux64/wa
./output/wa-lang-linux64/wa -h
#./output/wa-lang-linux64/wa waroot/hello.wa
#./output/wa-lang-linux64/wa run waroot/examples/prime
#./output/wa-lang-linux64/wa run waroot/hello.wa
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中7天后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:
- ./output
- step: publish@general_artifacts
name: publish_general_artifacts
displayName: 上传制品
# 上游构建任务定义的产物名默认BUILD_ARTIFACT
dependArtifact: BUILD_ARTIFACT
# 上传到制品库时的制品命名默认output
artifactName: output
dependsOn: build_golang
triggers:
pr:
branches:
include:
- master

View File

@ -1,15 +1,35 @@
# 版权 @2019 凹语言 作者。保留所有权利。
hello:
go run main.go run hello.wa
go install
cd waroot && go run ../main.go run hello.wa
prime:
go run main.go run _examples/prime
cd waroot && go run ../main.go run examples/prime
build-wasm:
GOARCH=wasm GOOS=js go build -o wa.out.wasm ./main_wasm.go
win-exe-icon:
windres -o main_rc_windows.syso main.rc
arduino-run:
go run main.go -target=arduino arduino.wa
arduino-build:
go run main.go build -target=arduino arduino.wa
wat2wasm a.out.wat -o a.out.wasm
xxd -i a.out.wasm > app.wasm.h
ci-test-all:
go install
go test ./...
@echo "== std test begin =="
go run main.go test std
@echo "== std ok =="
go run main.go run ./waroot/hello.wa
cd waroot && go run ../main.go run hello.wa
make -C ./waroot/examples ci-test-all
clean:
-rm a.out*

151
README-zh.md Normal file
View File

@ -0,0 +1,151 @@
<div align="center">
<h1>凹语言</h1>
[主页](https://wa-lang.org) | [Playground](https://wa-lang.org/playground) | [路线](https://wa-lang.org/smalltalk/st0001.html) | [社区](https://wa-lang.org/community) | [日志](https://wa-lang.org/guide/changelog.html)
</div>
凹语言凹读音“Wā”是 针对 WASM 平台设计的通用编程语言,同时支持 Linux、macOS 和 Windows 等主流操作系统和 Chrome 等浏览器环境,同时也支持作为独立 Shell 脚本和被嵌入脚本模式执行。
![](docs/images/logo/logo-animate1.svg)
- 主页: [https://wa-lang.org](https://wa-lang.org)
- 参考手册: [https://wa-lang.org/man/](https://wa-lang.org/man/)
- 仓库(Gitee): [https://gitee.com/wa-lang/wa](https://gitee.com/wa-lang/wa)
- 仓库(Github): [https://github.com/wa-lang/wa](https://github.com/wa-lang/wa)
- Playground: [https://wa-lang.org/playground](https://wa-lang.org/playground)
> 说明: 除非特别声明,凹语言代码均以 AGPL-v3 开源协议授权, 具体可以参考 LICENSE 文件。
## 如何参与开发
项目尚处于原型开源阶段如果有共建和PR需求请参考 [如何贡献代码](https://wa-lang.org/community/contribute.html)。我们不再接受针对第三方依赖库修改的 PR。
> 特别注意向本仓库提交PR视同您认可并接受[凹语言贡献者协议](https://gitee.com/organizations/wa-lang/cla/wca)但在实际签署之前您的PR不会被评审或接受。
## Playground 在线预览
[https://wa-lang.org/playground](https://wa-lang.org/playground)
![](https://wa-lang.org/playground-01.png)
## 贪吃蛇游戏
- [https://wa-lang.org/wa/snake/](https://wa-lang.org/wa/snake/)
- [https://wa-lang.org/smalltalk/st0018.html](https://wa-lang.org/smalltalk/st0018.html)
![](https://wa-lang.org/st0018-03.jpg)
## 例子: 凹语言
打印字符和调用函数:
```wa
import "fmt"
global year: i32 = 2023
func main {
println("hello, Wa!")
println(add(40, 2), year)
fmt.Println(1+1)
}
func add(a: i32, b: i32) => i32 {
return a+b
}
```
运行并输出结果:
```
$ wa run hello.wa
你好,凹语言!
42 2023
2
```
## 例子: 打印素数
打印 30 以内的素数:
```wa
// 版权 @2021 凹语言™ 作者。保留所有权利。
func main {
for n := 2; n <= 30; n = n + 1 {
isPrime: int = 1
for i := 2; i*i <= n; i = i + 1 {
if x := n % i; x == 0 {
isPrime = 0
}
}
if isPrime != 0 {
println(n)
}
}
}
```
运行并输出结果:
```
$ cd waroot && wa run examples/prime
2
3
5
7
11
13
17
19
23
29
```
## 例子:用中文语法打印素数
```wz
引于 "书"
【启】:
// 打印30以内的素数
从n=2到n>30有n++
设素=1
从i=2到i*i>n有i++
设x=n%i
若x==0则
素=0
若素!=0则
书·曰n
```
运行的结果和英文语法的示例相同。
更多例子 [waroot/examples](waroot/examples)
## 贡献者名单
|贡献者|贡献点|
| --- | --- |
|柴树杉| 35000|
|丁尔男| 42500|
|史斌 | 29000|
|扈梦明| 14000|
|赵普明| 17000|
|宋汝阳| 2000|
|刘云峰| 1000|
|王湘南| 1000|
|王泽龙| 1000|
|吴烜 | 3000|
|刘斌 | 2500|
|尹贻浩| 2000|
贡献点变更记录见 [waroot/cplog](waroot/cplog) 目录。

133
README.md
View File

@ -1,92 +1,82 @@
<div align="center">
<h1>🇨🇳 凹语言™ The Wa Programming Language</h1>
<h1>The Wa Programming Language</h1>
[主页](https://wa-lang.org) | [Playground](https://wa-lang.org/playground) | [目标](https://wa-lang.org/goals.html) | [路线](https://wa-lang.org/smalltalk/st0002.html) | [社区](https://wa-lang.org/community) | [日志](https://wa-lang.org/changelog.html) | [论坛](https://github.com/wa-lang/wa/discussions)
[Document](https://wa-lang.org) | [Playground](https://wa-lang.org/playground) | [Goals](https://wa-lang.org/goals.html) | [Roadmap](https://wa-lang.org/smalltalk/st0002.html) | [Community](https://wa-lang.org/community) | [Changelog](https://wa-lang.org/changelog.html) | [Discussions](https://github.com/wa-lang/wa/discussions)
[简体中文](https://github.com/wa-lang/wa/blob/master/README-zh.md) | [English](https://github.com/wa-lang/wa/blob/master/README.md)
</div>
<div align="center">
[![Build Status](https://github.com/wa-lang/wa/actions/workflows/wa.yml/badge.svg)](https://github.com/wa-lang/wa/actions/workflows/wa.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/wa-lang/wa)](https://goreportcard.com/report/github.com/wa-lang/wa)
[![Coverage Status](https://coveralls.io/repos/github/wa-lang/wa/badge.svg)](https://coveralls.io/github/wa-lang/wa)
[![GitHub release](https://img.shields.io/github/v/tag/wa-lang/wa.svg?label=release)](https://github.com/wa-lang/wa/releases)
[![Go Reference](https://pkg.go.dev/badge/github.com/wa-lang/wa.svg)](https://pkg.go.dev/github.com/wa-lang/wa)
[![license](https://img.shields.io/github/license/wa-lang/wa.svg)](https://github.com/wa-lang/wa/blob/master/LICENSE)
</div>
凹语言™凹读音“Wa”是 针对 WASM 平台设计的通用编程语言,同时支持 Linux、macOS 和 Windows 等主流操作系统和 Chrome 等浏览器环境同时也支持作为独立Shell脚本和被嵌入脚本模式执行。
Wa is a general-purpose programming language designed for developing robustness and maintainability WebAssembly software.
Instead of requiring complex toolchains to set up, you can simply go install it - or run it in a browser.
![](docs/images/logo/logo-animate1-blue.svg)
![](docs/images/logo/logo-animate1.svg)
- 主页 (Homepage): [https://wa-lang.org](https://wa-lang.org)
- 代码仓库 (Github): [https://github.com/wa-lang/wa](https://github.com/wa-lang/wa)
- 代码仓库 (Gitee): [https://gitee.com/wa-lang/wa](https://gitee.com/wa-lang/wa)
- Go 参考文档: [https://pkg.go.dev/github.com/wa-lang/wa](https://pkg.go.dev/github.com/wa-lang/wa)
- 开发工具 (Develop Tools): [Playground](https://wa-lang.org/playground), [VSCode 插件](https://marketplace.visualstudio.com/items?itemName=xxxDeveloper.vscode-wa), [Fleet 插件](https://github.com/wa-lang/fleet-wa), [Vim 插件](https://github.com/wa-lang/vim-wa)
- 开发组 (Core Team): [柴树杉(chai2010)](https://github.com/chai2010)、[丁尔男(Ending)](https://github.com/3dgen)、[史斌(Benshi)](https://github.com/benshi001)、[扈梦明(xxxDeveloper)](https://github.com/xxxDeveloper)、[刘云峰(leaftree)](https://github.com/leaftree)、[宋汝阳(ShiinaOrez)](https://github.com/ShiinaOrez)
- Home: [https://wa-lang.github.io/](https://wa-lang.github.io/)
- Manual: [https://wa-lang.github.io/man/en/](https://wa-lang.github.io/man/en/)
- Github: [https://github.com/wa-lang/wa](https://github.com/wa-lang/wa)
- Playground: [https://wa-lang.org/playground](https://wa-lang.org/playground)
## Playground 在线预览
> Note: Our canonical Git repository is located at https://gitee.com/wa-lang/wa. There is a mirror of the repository at https://github.com/wa-lang/wa. Unless otherwise noted, the Wa source files are distributed under the AGPL-v3 license found in the LICENSE file.
## Playground
[https://wa-lang.org/playground](https://wa-lang.org/playground)
![[![](https://wa-lang.org/smalltalk/images/st0011-01.png)](https://wa-lang.org/playground)](https://wa-lang.org/static/images/playground.gif)
![](https://wa-lang.org/playground-01.png)
## Snake Game
## 本地安装和测试 (Install and Run):
- Play: [https://wa-lang.org/wa/snake/](https://wa-lang.org/wa/snake/)
- Code: [waroot/examples/snake/README-en.md](waroot/examples/snake/README-en.md)
1. `go install github.com/wa-lang/wa@latest`
2. `wa init -name=_examples/hi`
3. `wa run _examples/hi`
![](https://wa-lang.org/st0018-03.jpg)
> 项目尚处于原型开源阶段如果有共建和PR需求请参考 [如何贡献代码](https://wa-lang.org/community/contribute.html)。
## Example: Print Wa
> The Wa project is still in very early stage. If you want to submit PR, please read the [Contribution Guide(Chinese)](https://wa-lang.org/community/contribute.html).
## 例子: 凹语言 (Example: Print 凹语言)
打印字符和调用函数(Print rune and call function)
Print rune and call function
```wa
import "fmt"
fn main {
println("你好,凹语言!")
println(add(40, 2))
global year: i32 = 2023
func main {
println("hello, Wa!")
println(add(40, 2), year)
fmt.Println(1+1)
}
fn add(a: i32, b: i32) => i32 {
func add(a: i32, b: i32) => i32 {
return a+b
}
```
运行并输出结果 (Execute the program):
Execute the program:
```
$ go run main.go hello.wa
你好,凹语言!
42
$ wa run hello.wa
hello, Wa!
42 2023
2
```
## 例子: 打印素数 (Example: Print Prime)
## Example: Print Prime
打印 30 以内的素数 (Print prime numbers up to 30):
Print prime numbers up to 30:
```
# 版权 @2021 凹语言™ 作者。保留所有权利。
fn main {
```wa
func main {
for n := 2; n <= 30; n = n + 1 {
var isPrime int = 1
isPrime: int = 1
for i := 2; i*i <= n; i = i + 1 {
if x := n % i; x == 0 {
isPrime = 0
@ -99,10 +89,10 @@ fn main {
}
```
运行并输出结果 (Execute the program):
Execute the program:
```
$ go run main.go run _examples/prime
$ cd waroot && wa run examples/prime
2
3
5
@ -115,28 +105,47 @@ $ go run main.go run _examples/prime
29
```
更多例子 (More examples) [_examples](_examples)
## Example: Print Prime with Chinese syntax
## 作为脚本执行 (Execut as a script)
Print prime numbers up to 30:
凹语言本身也可以像 Lua 语言被嵌入 Go 宿主语言环境执行 (The Wa language itself can also be executed like the Lua language embedded in the Go host locale):
```wz
引于 "书"
```
package main
import (
"fmt"
"github.com/wa-lang/wa/api"
)
func main() {
output, err := api.RunCode("hello.wa", "fn main() { println(40+2) }")
fmt.Print(string(output), err)
}
【启】:
// 输出30以内的素数
从n=2到n>30有n++
设素=1
从i=2到i*i>n有i++
设x=n%i
若x==0则
素=0
若素!=0则
书·曰n
```
注:作为脚本执行目前只支持本地环境。(Note: Executing as a script currently only supports native environments.)
Output is the same as the previous example.
## 版权(License)
More examples [waroot/examples](waroot/examples)
版权 @2019-2022 凹语言™ 作者。保留所有权利。(Copyrighe @2019-2022 The Wa author. All rights reserved.)
## Contributors
|Contributor|Contribution points|
| --- | --- |
|柴树杉| 35000|
|丁尔男| 42500|
|史斌 | 29000|
|扈梦明| 14000|
|赵普明| 17000|
|宋汝阳| 2000|
|刘云峰| 1000|
|王湘南| 1000|
|王泽龙| 1000|
|吴烜 | 3000|
|刘斌 | 2500|
|尹贻浩| 2000|

View File

@ -1 +0,0 @@
版权 @2022 _examples/hello 作者。保留所有权利。

View File

@ -1,5 +0,0 @@
// 版权 @2022 _examples/hello 作者。保留所有权利。
fn Println(x int) {
println(x)
}

View File

@ -1,5 +0,0 @@
// 版权 @2022 _examples/hello 作者。保留所有权利。
fn Println(x int) {
println(x)
}

View File

@ -1,14 +0,0 @@
{
"name": "_examples/hello",
"pkgpath": "myapp",
"version": "0.0.1",
"authors": ["author", "author2"],
"description": "module description",
"readme": "README.md",
"homepage": "",
"repository": "",
"license": "",
"license_file": "LICENSE",
"keywords": [],
"categories": []
}

View File

@ -1,19 +0,0 @@
// Test the llvm backend.
// Test read/write arrays.
fn main() {
test_array(2, 4)
test_array(7, 9)
}
fn test_array(a int, b int) {
var arr [10][10]int
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
arr[i][j] = i * j
}
}
println("arr[", a, "][", b, "] = ", arr[a][b])
println("arr[", b, "][", a, "] = ", arr[b][a])
}

View File

@ -1,30 +0,0 @@
// Test the llvm backend.
// Test passing array type parameters.
const size = 32
type fff32 f32
var arr0 [size]fff32
var arr1 [size]fff32
fn test_init() {
for i := 0; i < size; i++ {
arr0[i] = fff32(i * i)
}
}
fn getarr0a(arr [size]fff32, i int) fff32 {
return arr[i]
}
fn getarr0b(arr *[size]fff32, i int) fff32 {
return arr[i]
}
fn main() {
test_init()
for i := 6; i < 20; i += 2 {
println(getarr0a(arr0, i), ", ", getarr0b(&arr0, i + 1))
}
}

View File

@ -1,30 +0,0 @@
// Test the llvm backend.
// Test return array type values.
const size = 32
type fff32 f32
var arr1 [size]fff32
fn makearr0a(i int) [size]fff32 {
var r [size]fff32
for j := 0; j < size; j++ {
r[j] = fff32(i * j)
}
return r
}
fn makearr0b(i int) *[size]fff32 {
for j := 0; j < size; j++ {
arr1[j] = 2000 - fff32(i * j)
}
return &arr1
}
fn main() {
r0, r1 := makearr0a(10), makearr0b(20)
for i := 6; i < 20; i += 2 {
println(r0[i], ", ", r1[i])
}
}

View File

@ -1,35 +0,0 @@
// Test the llvm backend.
// Test comparasions.
fn main() {
test_cmp0(20, 19)
test_cmp0(20, 20)
test_cmp1(-3, -3)
test_cmp1(-3, -4)
test_cmp2(10, 10)
test_cmp2(10, 10.0001)
}
fn test_cmp0(a u16, b u16) {
if a > b {
println(a, " > ", b)
} else {
println(a, " <= ", b)
}
}
fn test_cmp1(a i64, b i64) {
if a <= b {
println(a, " <= ", b)
} else {
println(a, " > ", b)
}
}
fn test_cmp2(a f64, b f64) {
if a != b {
println(a, " != ", b)
} else {
println(a, " == ", b)
}
}

View File

@ -1,27 +0,0 @@
// Test the llvm backend.
// Test integer -> integer convertion.
fn main() {
println(i32(convert_i32_to_i16(65537)))
println(u32(convert_i32_to_u16(65537)))
println(convert_i16_to_i32(100))
println(convert_i16_to_i32(-100))
println(convert_u16_to_i32(100))
println(convert_u16_to_i32(65530))
}
fn convert_i32_to_i16(a i32) i16 {
return i16(a)
}
fn convert_i32_to_u16(a i32) u16 {
return u16(a)
}
fn convert_i16_to_i32(a i16) i32 {
return i32(a)
}
fn convert_u16_to_i32(a u16) i32 {
return i32(a)
}

View File

@ -1,10 +0,0 @@
// Test the llvm backend.
// Test 'floating point' -> 'floating point' convertion.
fn convert_f64_to_f32(a f64) f32 {
return f32(a)
}
fn main() {
println(convert_f64_to_f32(3.1415926535))
}

View File

@ -1,17 +0,0 @@
// Test the llvm backend.
// Test integer -> 'floating point' convertion.
fn main() {
println(convert_i16_to_f64(100))
println(convert_i16_to_f64(-100))
println(convert_u16_to_f64(100))
println(convert_u16_to_f64(65530))
}
fn convert_i16_to_f64(a i16) f64 {
return f64(a)
}
fn convert_u16_to_f64(a u16) f64 {
return f64(a)
}

View File

@ -1,19 +0,0 @@
// Test the llvm backend.
// Test 'floating point' -> integer convertion.
fn main() {
println(convert_f64_to_i32(100.001))
println(convert_f64_to_u32(100.001))
println(convert_f64_to_i32(99.99))
println(convert_f64_to_u32(99.99))
println(convert_f64_to_i32(-100.001))
println(convert_f64_to_u32(-100.001))
}
fn convert_f64_to_i32(a f64) i32 {
return i32(a)
}
fn convert_f64_to_u32(a f64) u32 {
return u32(a)
}

View File

@ -1,29 +0,0 @@
// Test the llvm backend.
// Test float32 operations.
type fff32 f32
fn getPi() fff32 {
return 3.1415926535
}
fn getE() fff32 {
return 2.71828
}
fn minusf32(a fff32) fff32 {
return 0 - a
}
fn circle_area(r fff32) fff32 {
return r * r * 3.1415926
}
fn main() {
println(getPi())
println(getE())
println(minusf32(getPi()))
println(minusf32(-1.3))
println(circle_area(1.1))
println(circle_area(getE()))
}

View File

@ -1,15 +0,0 @@
// Test the llvm backend.
// Test global constants.
const gbegin = 10
const gend = 20
fn test_global_consts() {
for i := gbegin; i < gend; i++ {
println(i, " - ", gbegin, " = ", i - gbegin)
}
}
fn main() {
test_global_consts()
}

View File

@ -1,19 +0,0 @@
// Test the llvm backend.
// Test read/write global variables.
type ty0 struct {
v0 int
v1 float64
}
var gv0 ty0 = ty0{5555, 3.1415926}
var gv1 [4]int = [4]int{81, 82, 17, 76}
fn test_global_variable() {
println("gv0: {", gv0.v0, ", ", gv0.v1, "}")
println("gv1: {", gv1[0], ", ", gv1[1], ", ", gv1[2], ", ", gv1[3], "}")
}
fn main() {
test_global_variable()
}

View File

@ -1,25 +0,0 @@
// Test the llvm backend.
// Test read/write global variables.
type ty0 struct {
v0 int
v1 float64
}
var gv0 ty0 = ty0{5555, 3.1415926}
var gv1 [4]int = [4]int{81, 82, 17, 76}
fn test_global_variable() {
gv0.v0 = 8888
gv0.v1 = 2.71828
gv1[0] += 2
gv1[1] += 3
gv1[2] += 4
gv1[3] += 5
println("gv0: {", gv0.v0, ", ", gv0.v1, "}")
println("gv1: {", gv1[0], ", ", gv1[1], ", ", gv1[2], ", ", gv1[3], "}")
}
fn main() {
test_global_variable()
}

View File

@ -1,16 +0,0 @@
// Test the llvm backend.
fn main {
a := 0.0
for y := 1.5; y > -1.5; y = y - 0.2 {
for x := -1.5; x < 1.5; x = x + 0.1 {
a = x*x + y*y - 1.0
if a*a*a < x*x*y*y*y {
print("@")
} else {
print(" ")
}
}
println()
}
}

View File

@ -1,12 +0,0 @@
// Test the llvm backend.
// Test loops.
fn main() {
test_loop(10)
}
fn test_loop(a i16) {
for i := i16(0); i < a; i++ {
println(i, " * ", i, " = ", i * i)
}
}

View File

@ -1,14 +0,0 @@
// Test the llvm backend.
// Test loops.
fn main() {
test_loop(10, 10)
}
fn test_loop(a u64, b u64) {
for i := u64(0); i < a; i++ {
for j := u64(0); j < b; j++ {
println(i, " * ", j, " = ", i * j)
}
}
}

View File

@ -1,29 +0,0 @@
// Test the llvm backend.
// Test read/write via a pointer.
var gint0 int = 100
var gint1 int = 200
fn get_int_addr(a int) *int {
if a > 0 {
return &gint0
} else {
return &gint1
}
}
fn set_int(a *int) {
*a += 10
}
fn test_pointer(a int) {
println(gint0, ", ", gint1)
p := get_int_addr(a)
set_int(p)
println(gint0, ", ", gint1)
}
fn main() {
test_pointer(1)
test_pointer(-1)
}

View File

@ -1,15 +0,0 @@
// Test the llvm backend.
fn main() {
for n := 2; n <= 30; n = n + 1 {
var isPrime int = 1
for i := 2; i*i <= n; i = i + 1 {
if x := n % i; x == 0 {
isPrime = 0
}
}
if isPrime != 0 {
println(n)
}
}
}

View File

@ -1,6 +0,0 @@
// Test the llvm backend.
// Test printing strings.
fn main() {
println("您好,凹语言!\n\"Hello, wa-lang!\"")
}

View File

@ -1,22 +0,0 @@
// Test the llvm backend.
// Test printing integers.
fn main() {
println(test_calc1(6, 9, 8), ", ", 5, ", ", test_calc5(6, 9, 8))
}
fn test_calc0(a i32, b i32, c i32) i32 {
return (-a) * 5 / (b - c + 2)
}
fn test_calc1(a i32, b i32, c i32) i32 {
return test_calc0(a, b, c)
}
fn test_calc4(a u16, b u16, c u16) u16 {
return (-a) * 5 / (b - c + 2)
}
fn test_calc5(a u16, b u16, c u16) u16 {
return test_calc4(-a, b, c)
}

View File

@ -1,14 +0,0 @@
// Test the llvm backend.
// Test printing float64 values.
fn main() {
println(5.44, ", ", test_calc3(6, 9, 8))
}
fn test_calc2(a f64, b f64, c f64) f64 {
return (-a) * 5 / (b - c + 2)
}
fn test_calc3(a f64, b f64, c f64) f64 {
return test_calc2(a, b, c)
}

View File

@ -1,10 +0,0 @@
// Test the llvm backend.
// Test printing small type values.
fn main() {
test_print(-100, 100, -100, 100, 5)
}
fn test_print(a i16, b u16, c i8, d u8, e f32) {
println(a, ", ", b, ", ", c, ", ", d, ", ", e/2)
}

View File

@ -1,31 +0,0 @@
// Test the llvm backend.
// Test read/write structs.
fn main() {
test_struct(10)
test_struct(11)
test_struct(2)
test_struct(13)
test_struct(0)
}
type t0 struct {
a int64
b int32
c [4]f64
d uint32
}
fn test_struct(a int) {
s0 := t0{17, -668, [4]f64{2.71828, 0.717, 3.14159}, 234}
switch a {
case 10:
println(s0.a)
case 11:
println(s0.b)
case 13:
println(s0.d)
default:
println(s0.c[a])
}
}

View File

@ -1,31 +0,0 @@
// Test the llvm backend.
// Test read/write structs.
fn main() {
test_struct1(10, 0, 0)
test_struct1(11, 1, 0)
test_struct1(2, 0, 1)
test_struct1(13, 1, 0)
test_struct1(2, 1, 0)
}
type t0 struct {
a int64
b int32
c [4]f64
d uint32
}
fn test_struct1(a int, b int, c int) {
s0 := [2]t0{{11, -12, [4]f64{0.1, -0.2}, 13}, {21, -22, [4]f64{1.1, -1.2}, 24}}
switch a {
case 10:
println(s0[b].a)
case 11:
println(s0[b].b)
case 13:
println(s0[b].d)
default:
println(s0[b].c[c])
}
}

View File

@ -1,35 +0,0 @@
// Test the llvm backend.
// Test passing struct type parameters.
type fff32 f32
const size = 16
type struct_t0 struct {
arr0 [size]int
arr1 [size]fff32
}
var st0 struct_t0
fn test_init() {
for i := 0; i < size; i++ {
st0.arr0[i] = i * i
st0.arr1[i] = fff32(i) * 2.0
}
}
fn getst0int(st0 struct_t0, i int) int {
return st0.arr0[i]
}
fn getst0f32(st0 *struct_t0, i int) fff32 {
return st0.arr1[i]
}
fn main() {
test_init()
for i := 6; i < 14; i += 2 {
println(getst0int(st0, i), ", ", getst0f32(&st0, i + 1))
}
}

View File

@ -1,35 +0,0 @@
// Test the llvm backend.
// Test return struct type values.
const size = 16
type struct_t0 struct {
arr0 [size]int
arr1 [size]f32
}
var st1 struct_t0
fn maket0a(i int) struct_t0 {
var r struct_t0
for j := 0; j < 16; j++ {
r.arr0[j] = 100 - j - i
r.arr1[j] = 200.0 - f32(j + i)
}
return r
}
fn maket0b(i int) *struct_t0 {
for j := 0; j < 16; j++ {
st1.arr0[j] = 100 - j - i
st1.arr1[j] = 200.0 - f32(j + i)
}
return &st1
}
fn main() {
r0, r1 := maket0a(20), maket0b(30)
for i := 0; i < 16; i++ {
println(r0.arr0[i], ", ", r0.arr1[i], " : ", r1.arr0[i], ", ", r1.arr1[i])
}
}

View File

@ -1,16 +0,0 @@
// Test the llvm backend.
// Test unconditional jump.
fn main() {
test_jmp(4)
}
fn test_jmp(a i32) {
for {
if a > 10 {
return
}
println(a)
a++
}
}

View File

@ -1,18 +0,0 @@
# 版权 @2022 凹语言 作者。保留所有权利。
fn main {
test_array(2, 4)
test_array(7, 9)
}
fn test_array(a: int, b: int) {
var arr [10][10]int
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
arr[i][j] = i * j
}
}
println("arr[", a, "][", b, "] = ", arr[a][b])
println("arr[", b, "][", a, "] = ", arr[b][a])
}

View File

@ -1,428 +0,0 @@
# 版权 @2022 凹语言 作者。保留所有权利。
fn main {
println("您好,凹语言!\nHello, wa-lang!")
println("幸运整数:", test_calc1(6, 9, 8), ", ", 5, ", ", test_calc5(6, 9, 8))
println("幸运浮点数:", 5.44, ", ", test_calc3(6, 9, 8))
test_print(-100, 100, -100, 100, 5)
test_cmp0(20, 19)
test_cmp0(20, 20)
test_cmp1(-3, -3)
test_cmp1(-3, -4)
test_cmp2(10, 10)
test_cmp2(10, 10.0001)
test_jmp(4)
test_loop0(10)
test_loop1(10, 10)
test_array(2, 4)
test_array(7, 9)
test_struct0(10)
test_struct0(11)
test_struct0(2)
test_struct0(13)
test_struct0(0)
test_struct1(10, 0, 0)
test_struct1(11, 1, 0)
test_struct1(2, 0, 1)
test_struct1(13, 1, 0)
test_struct1(2, 1, 0)
test_convert0()
test_convert1()
test_convert2()
test_convert3()
test_global_consts()
test_global_variables_0()
test_global_variables_1()
test_pointer(1)
test_pointer(-1)
test_f32()
test_struct2()
test_struct3()
test_struct4()
test_array2()
test_array3()
test_array4()
bye()
}
fn bye() {
println("再见!\nbye!")
}
fn test_calc0(a i32, b i32, c i32) i32 {
return (-a) * 5 / (b - c + 2)
}
fn test_calc1(a i32, b i32, c i32) i32 {
return test_calc0(a, b, c)
}
fn test_calc2(a f64, b f64, c f64) f64 {
return (-a) * 5 / (b - c + 2)
}
fn test_calc3(a f64, b f64, c f64) f64 {
return test_calc2(a, b, c)
}
fn test_calc4(a u16, b u16, c u16) u16 {
return (-a) * 5 / (b - c + 2)
}
fn test_calc5(a u16, b u16, c u16) u16 {
return test_calc4(-a, b, c)
}
fn test_cmp0(a u16, b u16) {
if a > b {
println(a, " > ", b)
} else {
println(a, " <= ", b)
}
}
fn test_cmp1(a i64, b i64) {
if a <= b {
println(a, " <= ", b)
} else {
println(a, " > ", b)
}
}
fn test_cmp2(a f64, b f64) {
if a != b {
println(a, " != ", b)
} else {
println(a, " == ", b)
}
}
fn test_jmp(a i32) {
for {
if a > 10 {
return
}
println(a)
a++
}
}
fn test_loop0(a i16) {
for i := i16(0); i < a; i++ {
println(i, " * ", i, " = ", i * i)
}
}
fn test_loop1(a u64, b u64) {
for i := u64(0); i < a; i++ {
for j := u64(0); j < b; j++ {
println(i, " * ", j, " = ", i * j)
}
}
}
fn test_array(a int, b int) {
var arr [10][10]int
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
arr[i][j] = i * j
}
}
println("arr[", a, "][", b, "] = ", arr[a][b])
println("arr[", b, "][", a, "] = ", arr[b][a])
}
type t0 struct {
a int64
b int32
c [4]f64
d uint32
}
fn test_struct0(a int) {
s0 := t0{17, -668, [4]f64{2.71828, 0.717, 3.14159}, 234}
switch a {
case 10:
println(s0.a)
case 11:
println(s0.b)
case 13:
println(s0.d)
default:
println(s0.c[a])
}
}
fn test_struct1(a int, b int, c int) {
s0 := [2]t0{{11, -12, [4]f64{0.1, -0.2}, 13}, {21, -22, [4]f64{1.1, -1.2}, 24}}
switch a {
case 10:
println(s0[b].a)
case 11:
println(s0[b].b)
case 13:
println(s0[b].d)
default:
println(s0[b].c[c])
}
}
type struct_t0 struct {
arr0 [16]int
arr1 [16]f32
}
var st0 struct_t0
var st1 struct_t0
fn test_struct2() {
for i := 0; i < 16; i++ {
st0.arr0[i] = i * i
st0.arr1[i] = f32(i) * 2.0
}
}
fn getst0int(st0 struct_t0, i int) int {
return st0.arr0[i]
}
fn getst0f32(st0 *struct_t0, i int) f32 {
return st0.arr1[i]
}
fn test_struct3() {
for i := 6; i < 14; i += 2 {
println(getst0int(st0, i), ", ", getst0f32(&st0, i + 1))
}
}
fn maket0a(i int) struct_t0 {
var r struct_t0
for j := 0; j < 16; j++ {
r.arr0[j] = 100 - j - i
r.arr1[j] = 200.0 - f32(j + i)
}
return r
}
fn maket0b(i int) *struct_t0 {
for j := 0; j < 16; j++ {
st1.arr0[j] = 100 - j - i
st1.arr1[j] = 200.0 - f32(j + i)
}
return &st1
}
fn test_struct4() {
r0, r1 := maket0a(20), maket0b(30)
for i := 0; i < 16; i++ {
println(r0.arr0[i], ", ", r0.arr1[i], " : ", r1.arr0[i], ", ", r1.arr1[i])
}
}
type fff32 f32
var arr0 [32]fff32
var arr1 [32]fff32
fn test_array2() {
for i := 0; i < 32; i++ {
arr0[i] = fff32(i * i)
}
}
fn getarr0a(arr [32]fff32, i int) fff32 {
return arr[i]
}
fn getarr0b(arr *[32]fff32, i int) fff32 {
return arr[i]
}
fn makearr0a(i int) [32]fff32 {
var r [32]fff32
for j := 0; j < 32; j++ {
r[j] = fff32(i * j)
}
return r
}
fn makearr0b(i int) *[32]fff32 {
for j := 0; j < 32; j++ {
arr1[j] = 2000 - fff32(i * j)
}
return &arr1
}
fn test_array3() {
for i := 6; i < 20; i += 2 {
println(getarr0a(arr0, i), ", ", getarr0b(&arr0, i + 1))
}
}
fn test_array4() {
r0, r1 := makearr0a(10), makearr0b(20)
for i := 6; i < 20; i += 2 {
println(r0[i], ", ", r1[i])
}
}
fn convert_i32_to_i16(a i32) i16 {
return i16(a)
}
fn convert_i32_to_u16(a i32) u16 {
return u16(a)
}
fn convert_i16_to_i32(a i16) i32 {
return i32(a)
}
fn convert_u16_to_i32(a u16) i32 {
return i32(a)
}
fn test_convert0() {
println(i32(convert_i32_to_i16(65537)))
println(u32(convert_i32_to_u16(65537)))
println(convert_i16_to_i32(100))
println(convert_i16_to_i32(-100))
println(convert_u16_to_i32(100))
println(convert_u16_to_i32(65530))
}
fn convert_f64_to_f32(a f64) f32 {
return f32(a)
}
fn test_convert1() {
println(f64(convert_f64_to_f32(3.1415926535)))
}
fn convert_i16_to_f64(a i16) f64 {
return f64(a)
}
fn convert_u16_to_f64(a u16) f64 {
return f64(a)
}
fn test_convert2() {
println(convert_i16_to_f64(100))
println(convert_i16_to_f64(-100))
println(convert_u16_to_f64(100))
println(convert_u16_to_f64(65530))
}
fn convert_f64_to_i32(a f64) i32 {
return i32(a)
}
fn convert_f64_to_u32(a f64) u32 {
return u32(a)
}
fn test_convert3() {
println(convert_f64_to_i32(100.001))
println(convert_f64_to_u32(100.001))
println(convert_f64_to_i32(99.99))
println(convert_f64_to_u32(99.99))
println(convert_f64_to_i32(-100.001))
println(convert_f64_to_u32(-100.001))
}
fn test_print(a i16, b u16, c i8, d u8, e f32) {
println(a, ", ", b, ", ", c, ", ", d, ", ", e/2)
}
const gbegin = 10
const gend = 20
fn test_global_consts() {
for i := gbegin; i < gend; i++ {
println(i, " - ", gbegin, " = ", i - gbegin)
}
}
type ty0 struct {
v0 int
v1 float64
}
var gv0 ty0 = ty0{5555, 3.1415926}
var gv1 [4]int = [4]int{81, 82, 17, 76}
fn test_global_variables_0() {
println("gv0: {", gv0.v0, ", ", gv0.v1, "}")
println("gv1: {", gv1[0], ", ", gv1[1], ", ", gv1[2], ", ", gv1[3], "}")
}
fn test_global_variables_1() {
gv0.v0 = 8888
gv0.v1 = 2.71828
gv1[0] += 2
gv1[1] += 3
gv1[2] += 4
gv1[3] += 5
println("gv0: {", gv0.v0, ", ", gv0.v1, "}")
println("gv1: {", gv1[0], ", ", gv1[1], ", ", gv1[2], ", ", gv1[3], "}")
}
var gint0 int = 100
var gint1 int = 200
fn get_int_addr(a int) *int {
if a > 0 {
return &gint0
} else {
return &gint1
}
}
fn set_int(a *int) {
*a += 10
}
fn test_pointer(a int) {
println(gint0, ", ", gint1)
p := get_int_addr(a)
set_int(p)
println(gint0, ", ", gint1)
}
fn getPi() f32 {
return 3.1415926535
}
fn getE() f32 {
return 2.71828
}
fn minusf32(a f32) f32 {
return 0 - a
}
fn circle_area(r f32) f32 {
return r * r * 3.1415926
}
fn test_f32() {
println(getPi())
println(getE())
println(minusf32(getPi()))
println(minusf32(-1.3))
println(circle_area(1.1))
println(circle_area(getE()))
}

View File

@ -1,18 +0,0 @@
# 版权 @2021 凹语言 作者。保留所有权利。
fn main() {
p := new_int()
println(*p)
proc(p)
println(*p)
}
fn new_int() => *i32 {
var i: i32
i = 42
return &i
}
fn proc(i: *i32) {
*i = 13
}

View File

@ -1 +0,0 @@
版权 @2022 _examples/hello 作者。保留所有权利。

View File

@ -1,13 +0,0 @@
// 版权 @2022 _examples/hello 作者。保留所有权利。
type ST struct {
A: i32
B: string
}
var G ST
fn Do(x i32) {
G.A = x
G.B = "Hellow wa"
}

View File

@ -1,5 +0,0 @@
// 版权 @2022 _examples/hello 作者。保留所有权利。
fn Println(x int) {
println(x)
}

View File

@ -1,14 +0,0 @@
{
"name": "_examples/hello",
"pkgpath": "pkg",
"version": "0.0.1",
"authors": ["author", "author2"],
"description": "module description",
"readme": "README.md",
"homepage": "",
"repository": "",
"license": "",
"license_file": "LICENSE",
"keywords": [],
"categories": []
}

View File

@ -1,3 +0,0 @@
fn PrintInt(x int) {
print(x, " ")
}

View File

@ -1,10 +0,0 @@
// 版权 @2022 凹语言™ 作者。保留所有权利。
fn isPrime(n int) bool {
for i := 2; i*i <= n; i = i + 1 {
if n%i == 0 {
return false
}
}
return true
}

View File

@ -1,20 +0,0 @@
// 版权 @2022 凹语言™ 作者。保留所有权利。
import "examples/prime/benpkg"
import "joypkg"
fn main() {
for n := 2; n <= 100; n = n + 1 {
if isPrime(n) {
benpkg.PrintInt(n)
}
}
println("")
for n := 2; n <= 100; n = n + 1 {
if isPrime(n) {
joypkg.PrintIntComma(n)
}
}
println("")
}

View File

@ -1,3 +0,0 @@
fn PrintIntComma(x int) {
print(x, ",")
}

View File

@ -1,14 +0,0 @@
{
"name": "prime",
"pkgpath": "examples/prime",
"version": "0.0.1",
"authors": ["author", "author2"],
"description": "module description",
"readme": "README.md",
"homepage": "",
"repository": "",
"license": "",
"license_file": "LICENSE",
"keywords": [],
"categories": []
}

View File

@ -6,12 +6,12 @@ package api
import (
"io/fs"
"github.com/wa-lang/wa/internal/backends/compiler_wat"
"github.com/wa-lang/wa/internal/backends/target_spec"
"github.com/wa-lang/wa/internal/config"
"github.com/wa-lang/wa/internal/format"
"github.com/wa-lang/wa/internal/loader"
"github.com/wa-lang/wa/internal/logger"
"wa-lang.org/wa/internal/backends/compiler_wat"
"wa-lang.org/wa/internal/config"
"wa-lang.org/wa/internal/format"
"wa-lang.org/wa/internal/loader"
"wa-lang.org/wa/internal/logger"
"wa-lang.org/wa/internal/wamime"
)
// 调试参数
@ -42,26 +42,9 @@ type PkgVFS = config.PkgVFS
// 指针和整数大小
type StdSize = config.StdSizes
// 目标机器
type Machine = target_spec.Machine
const (
Machine_default = Machine_Wasm32_wa // 默认输出的目标类型
Machine_Wasm32_wa = target_spec.Machine_Wasm32_wa // 凹语言定义的 WASM 规范
Machine_Wasm32_wasi = target_spec.Machine_Wasm32_wasi // WASI 定义的 WASM 规范
)
// 解析字符串类型
func ParseMachine(s string) (target Machine, ok bool) {
switch t := Machine(s); t {
case Machine_Wasm32_wa:
return t, true
case Machine_Wasm32_wasi:
return t, true
default:
return "", false
}
// 默认配置
func DefaultConfig() *Config {
return config.DefaultConfig()
}
// 加载 WaModFile 文件
@ -89,36 +72,39 @@ func LoadProgramVFS(vfs *config.PkgVFS, cfg *config.Config, pkgPath string) (*Pr
}
// 构建 wat 目标
func BuildFile(filename string, src interface{}, target Machine) (wat []byte, err error) {
cfg := config.DefaultConfig()
func BuildFile(cfg *config.Config, filename string, src interface{}) (wat []byte, err error) {
prog, err := LoadProgramFile(cfg, filename, src)
if err != nil || prog == nil {
logger.Tracef(&config.EnableTrace_api, "LoadProgramVFS failed, err = %v", err)
return nil, err
}
watOut, err := compiler_wat.New().Compile(prog, target)
watOut, err := compiler_wat.New().Compile(prog, "main")
return []byte(watOut), err
}
// 构建 wat 目标
func BuildVFS(vfs *config.PkgVFS, appPkg string, target Machine) (wat []byte, err error) {
cfg := config.DefaultConfig()
func BuildVFS(cfg *config.Config, vfs *config.PkgVFS, appPkg string) (wat []byte, err error) {
prog, err := LoadProgramVFS(vfs, cfg, appPkg)
if err != nil || prog == nil {
logger.Tracef(&config.EnableTrace_api, "LoadProgramVFS failed, err = %v", err)
return nil, err
}
watOut, err := compiler_wat.New().Compile(prog, target)
watOut, err := compiler_wat.New().Compile(prog, "main")
return []byte(watOut), err
}
// 格式化代码
func FormatCode(filename, code string) (string, error) {
data, err := format.File(nil, filename, code)
data, _, err := format.File(nil, filename, code)
if err != nil {
return "", err
}
return string(data), nil
}
// 获取代码语法类型
func GetCodeSyntax(filename string, code []byte) string {
return wamime.GetCodeMime(filename, code)
}

View File

@ -6,26 +6,27 @@
package api
import (
"os"
"github.com/wa-lang/wa/internal/app/apputil"
"wa-lang.org/wa/internal/config"
"wa-lang.org/wa/internal/wabt"
"wa-lang.org/wa/internal/wazero"
)
// 执行凹代码
func RunCode(filename, code string) (stdoutStderr []byte, err error) {
func RunCode(cfg *config.Config, filename, code string, args ...string) (stdoutStderr []byte, err error) {
// 编译为 wat 格式
wat, err := BuildFile(filename, code, Machine_Wasm32_wa)
// wat 写到临时文件
outfile := "a.out.wat"
if !*FlagDebugMode {
defer os.Remove(outfile)
}
if err = os.WriteFile(outfile, []byte(wat), 0666); err != nil {
return nil, err
watBytes, err := BuildFile(cfg, filename, code)
if err != nil {
return
}
// 执行 wat 文件
stdoutStderr, err = apputil.RunWasm(outfile)
// wat 编译为 wasm
wasmBytes, err := wabt.Wat2Wasm(watBytes)
if err != nil {
return
}
// main 执行
stdout, stderr, err := wazero.RunWasm(cfg, filename, wasmBytes, args...)
stdoutStderr = append(stdout, stderr...)
return
}

View File

@ -6,23 +6,23 @@ import (
"fmt"
"log"
"github.com/wa-lang/wa/api"
"wa-lang.org/wa/api"
)
func ExampleRunCode() {
const code = `
var gBase: i32 = 1000
global gBase: i32 = 1000
fn main() {
func main() {
println(add(40, 2) + gBase)
}
fn add(a: i32, b: i32) => i32 {
func add(a: i32, b: i32) => i32 {
return a+b
}
`
output, err := api.RunCode("hello.wa", code)
output, err := api.RunCode(api.DefaultConfig(), "hello.wa", code)
if err != nil {
log.Fatal(err)
}
@ -32,3 +32,55 @@ func ExampleRunCode() {
// Output:
// 1042
}
func ExampleRunCode_args() {
const code = `
import "os"
func main {
for i, s := range os.Args[1:] {
println(i, ":", s)
}
}
`
args := []string{"aa", "bb"}
output, err := api.RunCode(api.DefaultConfig(), "hello.wa", code, args...)
if err != nil {
if len(output) != 0 {
log.Println(string(output))
}
log.Fatal(err)
}
fmt.Print(string(output))
// Output:
// 0 : aa
// 1 : bb
}
func ExampleRunCode_wz() {
const code = `
#wa:syntax=wz
引于 "书"
·"你好,凹语言中文版!"
`
output, err := api.RunCode(api.DefaultConfig(), "hello.wa", code)
if err != nil {
if len(output) != 0 {
log.Println(string(output))
}
log.Fatal(err)
}
fmt.Print(string(output))
// Output:
// 你好,凹语言中文版!
}

View File

@ -5,16 +5,16 @@ package api_test
import (
"fmt"
"github.com/wa-lang/wa/api"
"wa-lang.org/wa/api"
)
func ExampleFormatCode() {
s, err := api.FormatCode("hello.wa", "fn add(a:i32, b:i32)=>i32 {return a+b}")
s, err := api.FormatCode("hello.wa", "func add(a:i32, b:i32)=>i32 {return a+b}")
if err != nil {
panic(err)
}
fmt.Println(s)
// Output:
// fn add(a: i32, b: i32) => i32 { return a + b }
// func add(a: i32, b: i32) => i32 { return a + b }
}

54
api/consts.go Normal file
View File

@ -0,0 +1,54 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package api
import (
"wa-lang.org/wa/internal/config"
)
// wa 代码:
// xxx.wa
// xxx_$OS.wa
// xxx_$ARCH.wa
// xxx_$OS_$ARCH.wa
// wz 中文代码:
// xxx.wz
// xxx_$OS.wz
// xxx_$ARCH.wz
// xxx_$OS_$ARCH.wz
// ws 汇编代码:
// xxx.$BACKEND.ws
// xxx_$OS.$BACKEND.ws
// xxx_$ARCH.$BACKEND.ws
// xxx_$OS_$ARCH.$BACKEND.ws
// 编译器后端类型
const (
WaBackend_Default = config.WaBackend_Default // 默认
WaBackend_clang = config.WaBackend_clang // 输出 c
WaBackend_llvm = config.WaBackend_llvm // 输出 llir
WaBackend_wat = config.WaBackend_wat // 输出 wat
)
// 目标平台类型, 可管理后缀名
const (
WaOS_Default = config.WaOS_Default // 默认
WaOS_arduino = config.WaOS_arduino // Arduino 平台
WaOS_chrome = config.WaOS_chrome // Chrome 浏览器
WaOS_wasi = config.WaOS_wasi // WASI 接口
)
// 体系结构类型
const (
WaArch_Default = config.WaArch_Default // 默认
WaArch_386 = config.WaArch_386 // 386 平台
WaArch_amd64 = config.WaArch_amd64 // amd64 平台
WaArch_arm64 = config.WaArch_arm64 // arm64 平台
WaArch_riscv64 = config.WaArch_riscv64 // riscv64 平台
WaArch_wasm = config.WaArch_wasm // wasm 平台
)

View File

@ -9,11 +9,19 @@ import (
"fmt"
"os"
"github.com/wa-lang/wa/api"
"wa-lang.org/wa/api"
)
func main() {
output, err := api.RunCode("hello.wa", code)
output, err := api.RunCode(api.DefaultConfig(), "hello.wa", code)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Print(string(output))
output, err = api.RunCode(api.DefaultConfig(), "hello-zh.wz", code_zh)
if err != nil {
fmt.Println(err)
os.Exit(1)
@ -23,11 +31,19 @@ func main() {
}
const code = `
fn main() {
func main {
println(add(40, 2))
}
fn add(a: i32, b: i32) => i32 {
func add(a: i32, b: i32) => i32 {
return a+b
}
`
const code_zh = `
引于 "书"
·"你好,凹语言中文版!"
`

View File

@ -1,42 +0,0 @@
# 版本日志
- v0.3.1 (2022-11-16)
- 完善 WAT 后端, 支持多包
- LLVM 后端支持基本数值运算 (依赖 clang 和 llc)
- wazero 更新到 v1.0.0-pre.3 [#37](https://github.com/wa-lang/wa/pull/37)
- v0.3.0 (2022-10-28)
- 启用 AGPLv3 开源协议
- 增加 如何贡献代码 机制
- 语言: 实现字符串类型
- 启动 LLVM 后端
- v0.2.3 (2022-10-18)
- 支持 JetBrains Fleet 语法高亮
- Wat 后端改善对 Slice 支持
- v0.2.2 (2022-10-11)
- Windows 增加 exe 图标
- Playground 改进异步加载wasm资源, 支持多个例子
- Wat 后端改善全局变量支持
- 增加 `#wa:xxx` 模式注释, 支持通过凹语言实现底层的 runtime 函数
- 实验特性: 简化无参数和返回值函数定义
- v0.2.1 (2022-09-16)
- 支持纯浏览器编译执行: [https://wa-lang.org/playground](https://wa-lang.org/playground)
- 命令行增加打印 logo 子命令
- 本地支持被嵌入脚本模式执行
- 修复格式化问题
- v0.2.0 (2022-09-07)
- 全面切换到 WAT 后端, 支持 Linux/macOS/Windows 平台
- 简化命令行子命令, 不依赖任何第三方工具
- 暂时去掉对字符串和浮点数的例子
- v0.1.3 (2022-08-27)
- 去掉 CGO 依赖
- 去掉 `opa/wasm` 依赖
- `#` 改为单行注释
- 简化命令行, 命令行支持执行单个文件
- v0.1.2 (2022-08-15)
- 增加 `#` 作为空格等价字符
- v0.1.1 (2022-08-12)
- LET 改成 VAR
- v0.1.0 (2022-07-24)
- 开源, 包含 LLVM 后端, 可运行简单例子
- v0.0.0 (2018-00-00)
- 凹名字诞生

View File

@ -1,6 +1,6 @@
<!--
// 版权 @2019 凹语言 作者。保留所有权利。
// https://github.com/wa-lang
// https://wa-lang.org
-->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400" width="400" height="400" fill="none">
@ -15,7 +15,7 @@
<animate attributeName="r" values="0;5;5;0" dur="1s" repeatCount="1" />
</circle>
<path d="M200 230L234 264L268 230M200 230L166 264L132 230" stroke="white" stroke-width="8" stroke-linecap="round" stroke-dasharray="0,0,0,192">
<path d="M200 230L234 264L268 230M200 230L166 264L132 230" fill="none" stroke="white" stroke-width="8" stroke-linecap="round" stroke-dasharray="0,0,0,192">
<animate attributeType="XML" attributeName="stroke-dasharray" values="0,0,0,192;0,96,96,0; 192,0,0,0" keyTimes="0; 0.5;1" fill="freeze" dur="1.5s" repeatCount="1" />
</path>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,6 +1,6 @@
<!--
// 版权 @2019 凹语言 作者。保留所有权利。
// https://github.com/wa-lang
// https://wa-lang.org
-->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400" width="400" height="400" fill="none">
@ -15,7 +15,7 @@
<animate attributeName="r" values="0;5;5;0" dur="1s" repeatCount="1" />
</circle>
<path d="M200 230L234 264L268 230M200 230L166 264L132 230" stroke="white" stroke-width="8" stroke-linecap="round" stroke-dasharray="0,0,0,192">
<path d="M200 230L234 264L268 230M200 230L166 264L132 230" fill="none" stroke="white" stroke-width="8" stroke-linecap="round" stroke-dasharray="0,0,0,192">
<animate attributeType="XML" attributeName="stroke-dasharray" values="0,0,0,192;0,96,96,0; 192,0,0,0" keyTimes="0; 0.5;1" fill="freeze" dur="1.5s" repeatCount="1" />
</path>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,6 +1,6 @@
<!--
// 版权 @2019 凹语言 作者。保留所有权利。
// https://github.com/wa-lang
// https://wa-lang.org
-->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400" width="400" height="400" fill="none">

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 B

View File

@ -1,6 +1,7 @@
<!--
<!--
// 版权 @2019 凹语言 作者。保留所有权利。
// https://github.com/wa-lang
// https://wa-lang.org
-->
<svg xmlns="http://www.w3.org/2000/svg"

Before

Width:  |  Height:  |  Size: 635 B

After

Width:  |  Height:  |  Size: 628 B

View File

@ -1,6 +1,6 @@
<!--
// 版权 @2019 凹语言 作者。保留所有权利。
// https://github.com/wa-lang
// https://wa-lang.org
-->
<svg xmlns="http://www.w3.org/2000/svg"

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 619 B

View File

@ -1,6 +1,6 @@
<!--
// 版权 @2019 凹语言 作者。保留所有权利。
// https://github.com/wa-lang
// https://wa-lang.org
-->
<svg xmlns="http://www.w3.org/2000/svg"

Before

Width:  |  Height:  |  Size: 598 B

After

Width:  |  Height:  |  Size: 591 B

14
docs/index.html Normal file
View File

@ -0,0 +1,14 @@
<!doctype html>
<head>
<title>wa-lang/wa</title>
<!-- // 凹语言 go get 重定向 -->
<meta name="go-import" content="wa-lang.org/wa git https://github.com/wa-lang/wa">
<meta name="go-source" content="wa-lang.org/wa git https://github.com/wa-lang/wa https://github.com/wa-lang/wa/tree/master{/dir} https://github.com/wa-lang/wa/blob/master{/dir}/{file}#L{line}">
</head>
<div>
<h1>wa-lang/wa</h1>
<p>hello https://github.com/wa-lang/wa</p>
</div>

Binary file not shown.

410
docs/snake/index.css Normal file
View File

@ -0,0 +1,410 @@
* {
margin: 0;
padding: 0;
}
@font-face {
font-family: 'Rocher';
src: url('./RocherColorGX.woff2') format('woff2');
}
@font-palette-values --pink {
font-family: Rocher;
base-palette: 1;
}
@font-palette-values --mint {
font-family: Rocher;
base-palette: 7;
}
:root {
--wa-color: #00A39A;
--wa-bg: #2e2e2e;
--wa-bg2: #202020;
--wa-trans: translate(-50%, -50%);
--wa-handle-dir: calc(50% - 30px);
--wa-shadow:
rgb(45 35 66 / 40%) 0 2px 4px,
rgb(45 35 66 / 30%) 0 7px 13px -3px;
}
.tips {
position: absolute;
top: calc(50% - 355px);
left: calc(50% - 392px);
color: var(--wa-bg);
font-family: Rocher;
font-size: 2em;
font-palette: --mint;
}
#box {
background: var(--wa-color);
border-radius: 1em;
box-shadow: 0.2em 0.2em 2em rgba(46, 46, 46, 0.5);
padding: 0.5em;
position: absolute;
top: 50%;
left: 50%;
transform: var(--wa-trans)
}
#game {
background: var(--wa-color);
border-radius: 1em;
display: flex;
flex-direction: column;
position: relative;
}
#game::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow:
10px 10px 30px #006E67,
-10px -10px 40px #006E67,
inset -10px -10px 10px #008880,
inset 10px 10px 10px #008880,
inset 10px 10px 10px var(--wa-color);
filter: blur(3px);
}
.game__title {
font-size: 1.2em;
text-align: left;
padding: 0 0.6em;
margin: 0.2em 0;
display: block;
font-family: 'Rocher';
position: relative;
z-index: 1;
}
.game__title sup {
font-size: 0.6em;
color: #fff;
}
#game__screen {
background: var(--wa-bg);
box-shadow: var(--wa-shadow), var(--wa-bg2) 0 -3px 0 inset;
border-radius: 1em;
margin: 0 0.3em 0.3em;
padding: 0.6em;
display: flex;
justify-content: center;
align-items: center;
position: relative;
z-index: 1;
}
#game__screen-content {
width: 320px;
height: 320px;
border-radius: 0.5em;
overflow: hidden;
aspect-ratio: 1;
place-content: center;
background: #8C957B;
}
#game__operate {
flex: 1;
padding: 0.3em;
display: flex;
}
#game__operate-direction,
.game__operate-ghost {
margin: 0.5em;
width: 180px;
height: 180px;
position: relative;
}
#game__operate-direction .direction__item {
align-items: center;
appearance: none;
background: var(--wa-bg);
border-radius: 50%;
border-width: 0;
box-shadow: var(--wa-shadow), var(--wa-bg2) 0 -3px 0 inset;
height: 60px;
width: 60px;
position: absolute;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
white-space: nowrap;
will-change: box-shadow, transform;
}
#game__operate-direction .direction__item::after {
content: '';
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
}
#game__operate-direction .direction__item::before {
content: '';
display: block;
width: 0;
height: 0;
border-style: solid;
border-width: 0 0.5em 0.866em 0.5em;
border-color: transparent transparent #fff transparent;
position: absolute;
top: 50%;
left: 50%;
}
#game__operate-direction--up {
top: 0;
left: var(--wa-handle-dir);
}
#game__operate-direction--up::before {
transform: var(--wa-trans)
}
#game__operate-direction--right {
top: var(--wa-handle-dir);
right: 0;
}
#game__operate-direction--right::before {
transform: var(--wa-trans) rotate(90deg);
}
#game__operate-direction--down {
bottom: 0;
left: var(--wa-handle-dir);
}
#game__operate-direction--down::before {
transform: var(--wa-trans) rotate(180deg);
}
#game__operate-direction--left {
top: var(--wa-handle-dir);
left: 0;
}
#game__operate-direction--left::before {
transform: var(--wa-trans) rotate(270deg);
}
.game__operate-ghost {
border-radius: 50%;
background: rgba(46, 46, 46, 0.8);
box-shadow: var(--wa-shadow), var(--wa-bg2) 0 -3px 0 inset;
}
.game__operate-ghost::before {
content: '';
display: block;
width: 55px;
height: 55px;
background: var(--wa-bg);
position: absolute;
top: 50%;
left: 50%;
transform: var(--wa-trans);
z-index: 1;
}
.game__operate-ghost span {
background: var(--wa-bg);
height: 55px;
width: 55px;
position: absolute;
}
.game__operate-ghost span:nth-child(1) {
top: 10px;
left: 50%;
transform: translateX(-50%);
border-radius: 10px 10px 0 0;
box-shadow: var(--wa-shadow), var(--wa-bg2) -3px 0px 0 inset;
}
.game__operate-ghost span::before {
content: '';
display: block;
width: 0;
height: 0;
border-style: solid;
border-width: 0 10px 16px 10px;
border-color: transparent transparent var(--wa-bg2) transparent;
position: absolute;
top: 50%;
left: 50%;
}
.game__operate-ghost span:nth-child(1)::before {
transform: var(--wa-trans);
}
.game__operate-ghost span:nth-child(2) {
top: 50%;
left: 10px;
transform: translateY(-50%);
border-radius: 10px 0 0 10px;
box-shadow: var(--wa-shadow), var(--wa-bg2) 0px -3px 0 inset;
}
.game__operate-ghost span:nth-child(2)::before {
transform: var(--wa-trans) rotate(270deg);
}
.game__operate-ghost span:nth-child(3) {
top: 50%;
right: 10px;
transform: translateY(-50%);
border-radius: 0 10px 10px 0;
box-shadow: var(--wa-shadow), var(--wa-bg2) -3px 0px 0 inset;
}
.game__operate-ghost span:nth-child(3)::before {
transform: var(--wa-trans) rotate(90deg);
}
.game__operate-ghost span:nth-child(4) {
bottom: 10px;
left: 50%;
transform: translateX(-50%);
border-radius: 0 0 10px 10px;
box-shadow: var(--wa-shadow), var(--wa-bg2) -3px -3px 0 inset;
}
.game__operate-ghost span:nth-child(4)::before {
transform: var(--wa-trans) rotate(180deg);
}
.game__operate-assist {
flex: 1;
display: flex;
position: relative;
}
.game__operate-assist--btns {
position: absolute;
top: 0;
width: 8em;
height: 2em;
}
.game__operate-assist--btns span:nth-child(1)::before,
.game__operate-assist--btns span:nth-child(1)::after {
content: "";
position: absolute;
top: 0;
width: 3em;
height: 2em;
align-items: center;
appearance: none;
background: var(--wa-bg);
border-width: 0;
box-shadow: var(--wa-shadow), var(--wa-bg2) 0 -3px 0 inset;;
box-sizing: border-box;
height: 1em;
width: 3em;
border-radius: 0.5em;
}
.game__operate-assist--btns span:nth-child(1)::before {
left: 0.6em;
}
.game__operate-assist--btns span:nth-child(1)::after {
left: 4.6em;
}
.game__operate-assist--btns span:nth-child(2)::before,
.game__operate-assist--btns span:nth-child(2)::after {
position: absolute;
width: 3em;
height: 2em;
color: var(--wa-bg2);
font-size: 0.6em;
font-family: 'Rocher';
font-palette: --pink;
}
.game__operate-assist--btns span:nth-child(2)::before {
content: "SELECT";
top: 2em;
left: 1.4em;
}
.game__operate-assist--btns span:nth-child(2)::after {
content: "START";
top: 2em;
left: 8.4em;
}
.game__operate-assist--audio {
position: absolute;
bottom: 0;
width: 5em;
height: 3em;
margin: 0 0 0.6em 0.6em;
}
.game__operate-assist--audio::before {
--s: 6px;
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:radial-gradient(var(--wa-bg) 24%,#0000 15%);
background-size: var(--s) var(--s);
}
@media screen and (min-width: 768px) {
#box {
width: 768px;
max-width: 768px;
}
.game__title {
margin: 0.8em 0.2em;
}
.game__operate-assist {
flex-direction: column;
justify-content: space-between;
align-items: center;
}
}
@media screen and (max-width: 768px) {
.tips {
display: none;
}
#box {
width: 100%;
max-width: fit-content;
}
.game__operate-ghost {
display: none;
}
#game__operate-direction .direction__item:active {
box-shadow: var(--wa-bg2) 0 3px 7px inset;
transform: translateY(2px);
}
}

42
docs/snake/index.html Normal file
View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Wa: Snack Game</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<span class="tips">Please use the keyboard to control</span>
<div id="box">
<div id="game">
<span class="game__title">
Wa Snack Game
<sup><em>2022</em></sup>
</span>
<div id="game__screen">
<div id="game__screen-content"></div>
</div>
<div id="game__operate">
<div class="game__operate-ghost"><span></span><span></span><span></span><span></span></div>
<div class="game__operate-assist">
<span class="game__operate-assist--btns"><span></span><span></span></span>
<span class="game__operate-assist--audio"></span>
</div>
<div id="game__operate-direction">
<span id="game__operate-direction--up" class="direction__item"></span>
<span id="game__operate-direction--right" class="direction__item"></span>
<span id="game__operate-direction--down" class="direction__item"></span>
<span id="game__operate-direction--left" class="direction__item"></span>
</div>
</div>
</div>
</div>
</body>
<script type="text/javascript" src="./index.js"></script>
<script type="text/javascript" src="./wa_app.js"></script>
</html>

23
docs/snake/index.js Normal file
View File

@ -0,0 +1,23 @@
(() => {
document.documentElement.addEventListener('touchstart', (event) => {
if (event.touches.length > 1) { event.preventDefault(); }
}, { passive: false });
let lastTouchEnd = 0;
document.documentElement.addEventListener('touchend', (event) => {
let now = Date.now();
if (now - lastTouchEnd <= 500) { event.preventDefault() }
lastTouchEnd = now;
}, { passive: false });
})()
const IS_MOBILE = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
const DIR_ID_PREFIX = 'game__operate-direction--';
const MOBILE_DIR_MAP = [
{ id: `${DIR_ID_PREFIX}up`, keyCode: 38 },
{ id: `${DIR_ID_PREFIX}down`, keyCode: 40 },
{ id: `${DIR_ID_PREFIX}left`, keyCode: 37 },
{ id: `${DIR_ID_PREFIX}right`, keyCode: 39 },
];

BIN
docs/snake/snake.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

187
docs/snake/wa_app.js Normal file
View File

@ -0,0 +1,187 @@
(() => {
class WaApp {
constructor() {
this._inst = null;
this._wa_print_buf = "";
}
init(url) {
let app = this;
let importsObject = {
wasi_snapshot_preview1: new function () {
this.args_get = () => { return 0; }
this.args_sizes_get = () => { return 0; }
this.clock_res_get = () => { return 0; }
this.clock_time_get = () => { return 0; }
this.environ_get = () => { return 0; }
this.environ_sizes_get = () => { return 0; }
this.fd_advise = () => { return 0; }
this.fd_allocate = () => { return 0; }
this.fd_close = () => { return 0; }
this.fd_datasync = () => { return 0; }
this.fd_fdstat_get = () => { return 0; }
this.fd_fdstat_set_flags = () => { return 0; }
this.fd_fdstat_set_rights = () => { return 0; }
this.fd_filestat_get = () => { return 0; }
this.fd_filestat_set_size = () => { return 0; }
this.fd_filestat_set_times = () => { return 0; }
this.fd_pread = () => { return 0; }
this.fd_prestat_get = () => { return 0; }
this.fd_prestat_dir_name = () => { return 0; }
this.fd_pwrite = () => { return 0; }
this.fd_read = () => { return 0; }
this.fd_readdir = () => { return 0; }
this.fd_renumber = () => { return 0; }
this.fd_seek = () => { return 0; }
this.fd_sync = () => { return 0; }
this.fd_tell = () => { return 0; }
this.fd_write = () => { return 0; }
this.path_create_directory = () => { return 0; }
this.path_filestat_get = () => { return 0; }
this.path_filestat_set_times = () => { return 0; }
this.path_link = () => { return 0; }
this.path_open = () => { return 0; }
this.path_readlink = () => { return 0; }
this.path_remove_directory = () => { return 0; }
this.path_rename = () => { return 0; }
this.path_symlink = () => { return 0; }
this.path_unlink_file = () => { return 0; }
this.poll_oneoff = () => { return 0; }
this.proc_exit = () => { return 0; }
this.random_get = () => { return 0; }
this.sched_yield = () => { return 0; }
this.sock_accept = () => { return 0; }
this.sock_recv = () => { return 0; }
this.sock_send = () => { return 0; }
this.sock_shutdown = () => { return 0; }
},
wa_js_env: new function () {
this.waPrintI32 = (i) => {
app._wa_print_buf += i
}
this.waPrintRune = (c) => {
let ch = String.fromCodePoint(c);
if (ch == '\n') {
console.log(app._wa_print_buf);
app._wa_print_buf = "";
}
else {
app._wa_print_buf += ch
}
}
this.waPuts = (prt, len) => {
let s = app.getString(prt, len);
app._wa_print_buf += s
}
this.rand = (m) => {
return parseInt(Math.random() * m)
}
this.newCanvas = (w, h) => {
let canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
canvas.id = 0; //!!!!!
const waContent = document.getElementById('game__screen-content');
waContent.appendChild(canvas);
function getPointOnCanvas(x, y) {
var bbox = canvas.getBoundingClientRect();
return {
x: parseInt((x - bbox.left) * (canvas.width / bbox.width)),
y: parseInt((y - bbox.top) * (canvas.height / bbox.height))
};
}
function onMouseDown(ev) {
let pt = getPointOnCanvas(ev.clientX, ev.clientY);
app._inst.exports['snake$canvas.OnMouseDown'](canvas.id, pt.x, pt.y);
}
function onMouseUp(ev) {
let pt = getPointOnCanvas(ev.clientX, ev.clientY);
app._inst.exports['snake$canvas.OnMouseUp'](canvas.id, pt.x, pt.y);
}
function onKeyDown(ev) {
app._inst.exports['snake$canvas.OnKeyDown'](canvas.id, ev.keyCode);
}
function onKeyUp(ev) {
app._inst.exports['snake$canvas.OnKeyUp'](canvas.id, ev.keyCode);
}
if (IS_MOBILE) {
MOBILE_DIR_MAP.forEach((dir) => {
const el = document.getElementById(dir.id);
el.addEventListener('touchstart', (ev) => onKeyDown({ keyCode: dir.keyCode }));
el.addEventListener('touchend', (ev) => onKeyUp({ keyCode: dir.keyCode }));
});
}
canvas.addEventListener('mousedown', onMouseDown, true);
canvas.addEventListener('mouseup', onMouseUp, true);
canvas.addEventListener('keydown', onKeyDown, true);
canvas.addEventListener('keyup', onKeyUp, true);
canvas.tabIndex = -1; //tabindex
canvas.focus();
this._ctx = canvas.getContext('2d');
this._canvas = canvas;
return canvas.id;
}
this.updateCanvas = (id, block, data) => {
let img = this._ctx.createImageData(this._canvas.width, this._canvas.height);
let buf_len = this._canvas.width * this._canvas.height * 4
let buf = app.memUint8Array(data, buf_len);
for (var i = 0; i < buf_len; i++) {
img.data[i] = buf[i];
}
this._ctx.putImageData(img, 0, 0);
}
}
}
WebAssembly.instantiateStreaming(fetch(url), importsObject).then(res => {
this._inst = res.instance;
this._inst.exports._start();
const timer = setInterval(gameLoop, 150);
})
}
mem() {
return this._inst.exports.memory;
}
memView(addr, len) {
return new DataView(this._inst.exports.memory.buffer, addr, len);
}
memUint8Array(addr, len) {
return new Uint8Array(this.mem().buffer, addr, len)
}
getString(addr, len) {
return new TextDecoder("utf-8").decode(this.memView(addr, len));
}
setString(addr, len, s) {
const bytes = new TextEncoder("utf-8").encode(s);
if (len > bytes.length) { len = bytes.length; }
this.MemUint8Array(addr, len).set(bytes);
}
}
function gameLoop() {
window['waApp']._inst.exports['snake.Step']();
}
window['waApp'] = new WaApp();
window['waApp'].init("./snake.wasm")
})()

780
docs/wz/design.md Normal file
View File

@ -0,0 +1,780 @@
## 凹语言中文语法设计
## 理念
凹语言的中文语法(下面简称凹中文版)的设计理念是:
- 简洁:尽量减少冗余信息。例如:关键字尽量选择单字。
- 易读:代码读起来应当尽量贴近自然语言。关键语法信息应当足够醒目。
- 灵活:不必拘泥于英文编程语言的传统语法,可以尝试灵活的设计。
- 符号:作为中文编程语言,并不排除,而是妙用标点符号和拼音字母。
凹中文版的语法设计主要受到了[文言](https://wy-lang.org/)编程语言的启发。
但与文言编程语言的主要区别,在于上述的第一条理念:简洁。
我认为文言文相对于白话文,最大的特色就是简洁。
而简洁的需求正是由于时代的背景所决定的:当时的书写工具和文字承载工具都非常昂贵,因此惜字如金并不只是比喻。
因此,为了尽量继承文言文的简洁精神,我在设计凹中语法时,与文言编程语言的风格有了很大的区别。
凹中文版的语法设计还参考了:
- 凹英文语法。凹语言的中文和英文语法是相互兼容的,每个语法结构都能找到对应。并且到现在为止,凹中的解析前端还是和凹语言英文语法强耦合的。
- Go语言。凹语言初版的实现是用Go写的且前端代码也是从Go语言的前端移植过来的因此在设计与实现中会更倾向于贴近Go的风格。
- Kotlin和D语言。凹语言的中文语法设计中也借鉴了一些Kotlin和D的语法设计。
**提示**:凹中文版语法还处于早期探索阶段,很有可能会发生变化。
我们计划在完成凹中文前端的重构即完全脱离现有的Go前端之时得到一套稳定的中文语法。
现在可运行的示例,请参考凹语言工程中的[可执行示例](https://gitee.com/wa-lang/wa/tree/frontend_wz/waroot/examples/wz/)。
## 简单示例
下面是Hello World的凹中文版示例
```wz
引于 "书"
【启】:
书·说:“你好,凹语言!”
```
上面的代码中:
- `引于``import`)是关键字。
- `【】`是函数定义的标志,相当于`func`。
- `书·说:“你好,凹语言”`是函数调用,相当于:`fmt.println(“你好,凹语言!”)`
- ``和`。`是一个程序块的开始和结束符号。相当于`{`和`}`。
这些设计都是为了简洁和易读原则而做出的选择。
这段代码用凹英文版写出来就是:
```wa
import "fmt"
func main {
fmt.println("你好,凹语言!")
}
```
下面是一个更复杂的示例,展示了其他几个已经实现的基本语法:
```wz
引于 "书"
【启】:
// 基本函数调用
书·说:"你好,凹语言!"
// 调用自定义函数
书·说:"[自定义函数]40+2="
书·曰40、2
// 简单的条件判断
书·说:"[条件判断]"
设零之数 = 0
若零==1则
书·说:"是的零和1是相等的。"
否则:
书·说:"错了零和1是不同的。"
// 简单的自定义类型
设某=点{横:10, 纵:2}
书·说:"[自定义类型]点(10,2)的纵坐标和横坐标之和:"
书·曰:某·横 + 某·纵
书·说:"[自定义类型]点(10,2)的纵坐标和横坐标之平方和:"
书·曰:某·平方距:
// 循环
// 类似range
书·说:"[简单范围] 从0到3"
自0至3有i
书·曰i
// 类似三段式for循环注意由于中英文语义不同这里的j==8是停止条件和for循环的“持续条件”正好相反
书·说:"[循环语句] 从0到8"
从j=0到j==8有j++
书·曰j
书·说:"[循环语句] 从10到0"
设步=1
从i=10到i>=100
i+=步
书·曰i
// 类似until语句
书·说:"[直到语句] 直到5"
设i=0
直到i>=5
书·曰i
i++
// 多路选择
书·说:"[多路输出]k=3"
设k=3
当k
为1书·说"一"
为2书·说"二"
为3书·说"三"
否则:书·说:"不中"
《点》:
横之数
纵之数
【点·平方距】() => 数
归于:此·纵*此·纵 + 此·横*此·横
【加】(甲, 乙之数) => 数
归于:甲+乙
```
## 详细介绍
本节详细介绍上面几种语法的设计,以及为何这样设计的缘由。
### 函数定义和函数块
先看Hello World
```wz
引于 "书"
【启】:
书·说:“你好,凹语言!”
```
在凹中文版里,函数的定义用实心方括号`【】`来表达。方括号之中的是函数名称。
这里的`【启】`函数,是整个程序的启动函数,即我们常说的`主函数`。
本来我打算直接用以没有直接选择`【主】`,但写出来之后,这段代码读起来就有“主说:‘要有光’”的味道了,总有点怪怪的感觉。所以只好换了个字。
其实最开始我的设计几乎相当于对英文版的关键字替换:
```wz
函数 主函数 {
打印(“温故而知新,可以为师矣。”)
}
```
这里遇到了设计的第一个问题,直译的关键字变成中文之后读起来太过生硬了,而且也不够简洁。
这种风格的中文编程早就存在了,我相信这也是很多人一听到“中文编程”,就会产生的第一印象。
我认为这里有历史的原因,但也有习惯的原因。
”函数“、”打印“这种双字词,最开始翻译时,是用于技术文章,而不是程序的,因此简洁并不是翻译者的第一要务。
当时面对这些中文还没有的技术性新概念,采用这种翻译是非常合理的。
实际上,最早的英文编程语言中,关键字读起来也是冗长而生硬的:"procedure"后来被简化成proc”function“最近才简化成func\fun\fn
可以看出英文关键字的演变也是有一个从陌生到习惯、从冗长明确到简洁的过程的。
中文没法像英文那么容易缩略,但中文也有优势,我们有非常多的单字词可以选择。
因此我当时选择了”方“这个字,表示”方程、配方“的意味,用来替代”函数“;又选择了”曰“这个所有人都认识的单字来替代”打印“:
```wz
方 启 {
曰(”温故而知新,可以为师矣。“)
}
```
这样已经有一点”文言”编程语言的意味了。上面的代码完全可以用“文言”编程语言的风格来读:
```
吾有一方,其名曰【启】,其方如下:
一、曰:“温故而知新,可以为师矣。”
方止于此。
```
这个风格其实用来编程已经没有太大问题,既有简洁又清晰,相当于“文言”编程语言的简略版,其效用和英文版几乎一致。
但我多看了几趟,仍然觉得有点别扭。
再看看、再瞅瞅,终于发现别扭的地方了:我们没有适应过高度抽象话的中文编程,所以下意识还是会把它当做中文句子来读。
那么,不符合中文文本惯例的地方,就会显得有些跳脱,也就有了别扭感。
而这里最大的别扭感,来自于【空格】的使用。标准的中文文本里,是鲜有空格的。
我们的标点符号是全角,本身就自带了空白分隔。因此在这里用空格直接连接“方”和“启”字,就会有别扭感。
空格问题有两个解决办法:
一是把空格改成文本和标点,回归中文叙述。这也是“文言”编程语言选择的办法。因此即使它用的都是文言文,我们也觉得读起来比较顺畅。
但这个办法会增加大量冗余文字,在程序比较简单的时候还行,一旦比较复杂后,多出来的字词读起来就会浪费精力了;
另一个问题是这样平铺直述的表达是线性的,用来表示嵌套的逻辑时很难搞清楚层级。
第二个办法,就是巧妙地利用中文标点符号自带的空白,以他们来顶替空格的作用。
```wz
【启】:
曰:“温故而知新,可以为师矣。”
```
仔细观察,这里不论是实心方括号`【】`,还是中文冒号``,都既有充实的间隔感,又自带了空白,而且是符合中文阅读时内心的停顿节奏的空白。
因此即使我用了很奇怪的组合``和`。`来替代`{}`,都不会显得很别扭。
(实际上我最初选的结束符号是办公文本常见的`■`,这个符号本身就是结束符的意思。但由于这个符号远没有句号`。`好打出来,而它在凹中文版中又那么常用,因此我放弃它改用句号了。)
这个办法还有一个好处,类似`【】`这样的中文标点非常醒目,因此用来定位程序关键要素时很方便。读代码时,目光一扫就能感受到大概有几个函数。
看看上面的“文言”的例子,最抓眼球的字,是不是就是`【启】`?这也是为什么我选择实心方括号而不是空心的原因。
另外,由于`【】`的特殊性,我们连`方`这个关键词都可以不用了。
至此,读者应该还有一个问题,那问什么要把`{}`也换掉呢?
```wz
【启】{
曰(”温故而知新,可以为师矣。“)
}
```
这确实也是让我头疼的一个选择。'{'的作用本质上是开启新的名字空间。编程语言的名字空间是树状结构,`{}`开辟一个新的子空间,这里头可以继续引用上层的名称,但也可以新建只有自己(以及自己的子孙空间)才能访问的局部名称。要在程序中表达这样一个新的子空间,需要一个开始符号和一个结束符号。
常见的编程语言有三种方式来表达子空间:
- 括号。包括C系列语言的花括号`{}`和LISP系的`()`。
- 缩进。Python等语言采用的方法。优点是阅读的简洁性更强更符合自然语言习惯。缺点是层次太多以后容易搞错层级。
- 单独的`end`。Lua等语言用这个方法。很多时候开启新的子空间之前都有特殊的程序结构例如上面的“函数定义”所以不需要单独指定开启字符。但为了避免混淆需要指定一个结束字符。`end`就是最常用的结束关键词。这种方式比`{}`更接近自然语言的风格,同时也不用考虑缩进的问题,算是前两种方法的折衷。
我本来选择的是第三种:
```wz
【启】
曰(“温故而知新,可以为师矣。”)
```
但多看了几遍之后又觉得有点别扭,最后还是把`【启】`后面的冒号加上了:
```wz
【启】:
曰(“温故而知新,可以为师矣。”)
```
这个冒号虽然实际上是冗余的,但在阅读时提供的节奏感,我现在认为是必要的。
这样实际上又回归了和`{}`完全等效的局面:`:`对应`{``。`对应`}`。还挺合适。
最后一个问题,问什么用冒号来表示函数调用:
```wz
曰:“温故而知新,可以为师矣。”
```
```wz
曰(“温故而知新,可以为师矣。”)
```
再对比一下,其实没有本质的区别。非要说的话,怪我选的这个例子吧。实在是和《论语》 原文太像了:
```
子曰:“温故而知新,可以为师矣。”
```
这种平铺直叙的命令式,实在是太符合自然语言习惯了。
那么冒号会不会遇到问题呢?多个参数时怎么办?参数又是函数调用的嵌套时,又该怎么办?这个问题比较复杂,我会在后面函数相关的话题里专门描述。总之,一旦嵌套了,还是得有括号帮忙。
至此我们完成了HelloWorld的对比也大致了解了凹中文版在语法设计时所衡量的因素。接下来我们看看更复杂的情况。
### 变量
凹英文版变量的定义方式如下:
```wa
// 使用关键字var
var a: int = 1
a = a + 1
// 快速定义语法
b := 2
```
凹语言的变量定义和Go语言基本一致主要的区别在于变量和类型之间用`:`分隔更接近Kotlin等语言的风格。
在凹中文版中,用关键字“**设**”来表示变量的定义:
```wz
设甲=1
甲=甲+1
```
而用来赋值的操作符是`=`和英文版一致。
当然类似abc这样的拼音符号我认为在中文编程中并不需要避讳。因此上面的代码也可以写成
```wz
设a=1
a=a+1
```
要指明变量的类型,如果按照英文版的方式来的话,会是这样:
```wz
设a:数=1
a=a+1
```
但我感觉这样读起来会有些卡顿感。由于中文缺乏空格,这里的冒号就显得太突兀了。况且冒号已经用在代码块和函数调用上了。
解决办法有三种。
一种是变量和类型一起用括号包裹起来:
```wz
设(甲:数)=1
```
或者类似于函数定义,用独立的符号把变量名包裹起来,而不是包裹类型:
```wz
设「甲」数=1
```
第三种是直接把“**之**”字做成关键字,用来替代冒号:
```wz
设甲之数=1
```
现在暂时没有找到最佳的方案,我决定暂时用“**之**”关键字分隔的方式。等有了更多的代码体验之后,再确定正式方案。
### 数据类型
凹中文版最初版本只支持两个基本类型《数》和《文》。它们分别对应与Go语言的`int`和`string`类型。更多的类型支持,留待整个编译器雏形搭建好之后再慢慢扩充。
复合类型中最常见的是数组array和映射map
```wz
【启】:
// 数组
设a=[1,2,3]
// 映射
设b={1:2, 3:4, 5:6}
```
如果需要指明类型,则这么定义:
```wz
【启】:
// 数组
设a之[数]=[1,2,3]
// 映射
设b之{数:数}={1:2, 3:4, 5:6}
```
这里数组和映射的类型名称语法和英文版不一样。英文版沿用了Go的写法
- 数组:`[]int`
- 映射:`map[int]int`
而中文版则选择了和字面量几乎一致的形式。
- 数组:`[数]`
- 映射:`{数:数}`
这也得益于中文版并没有采用`{}`来表示代码块,因此可以把`{}`留给映射的类型标记用。
TODO: 这个功能暂时还没实现。
### 自定义函数
凹英文版定义函数的语法如下:
```wa
func add(a: int, b: int) => int {
return a+b
}
func main {
println(add(1, 2))
}
```
和Go语言类似但有两点区别
- 参数列表和返回类型之间有个`=>`符号分隔,这样让函数定义在整个文件中更醒目。当前版本这个`=>`是可以省略的。
- 如果函数参数为空,则可以把括号省略掉,比如这里的`func main`就直接接`{`了。
凹中文版的形式如下:
```wz
【和】a之数、b之数=> 数:
归于a+b
【启】:
1、2
```
这里:
- 【和】是函数名,`【】`表示定义一个新函数,相当于`func`。
- 参数列表和英文版基本一致,只不过参数的分隔由逗号`,`变成了顿号`、`。
- `归于:`是关键字,和`return`一样。
这里为什么选择和英文版几乎一致的形式?是因为我做过几个其他尝试之后,并没有找到更清晰且可读的方法。
因此在初始版本里,这么写已经足够好了。并且也符合凹中文版的设计原则:简洁、清晰可读且妙用了符号。因此我就不去特意发明新符号去替代了。
这里只有一个小遗憾,`=>`这个箭头在中文里是没有的,用英文版的话,也没有足够好的空间,必须在右侧加一个空格。我现在用的字体会自动把`=>`两个字符转换成`⇒`这一个字符的样子,因此看起来还比较和谐。但由于`⇒`这个字符没有办法直接输入,只能战术放弃。
### 函数的调用
函数的调用采用的是“:”加参数列表的格式,而不是传统语言中双括号的格式。
```
1、2
```
相当于`add(1, 2)`。
如果需要嵌套,可以用括号表示优先级:
```
5、2、3
```
相当于:`mul(5, add(2, 3))`
可以看到,凹中文版的函数调用语法的实际效用,和英文版并没有本质差别。
用``的主要好处是增加了简单调用的可读性,让普通代码中的一行行函数调用看起来更像是对话。但缺点是遇到复杂的调用组合,可能可读性不如英文版。我觉得这里也可能有习惯性的问题,所以打算先试用一段时间,看看是否真的有这个问题。
另外,函数调用的冒号和代码块的冒号是有冲突的,这一点需要再仔细验证一下。如果不行,可能考虑回归传统的`()`调用。
还有一个问题,即如果没有参数,该如何表示?
我暂时的设计是如果没有参数,还是回归`()`
```wz
【感叹】:
书·曰:“呜呼!”
【启】:
感叹()
```
总之,这里的设计还是不太成熟,需要再探讨探讨。
### 类型
用户自定义类型在高级编程语言中是非常重要的设计。很多设计模式都是依托于类型系统。
凹中文版的类型系统基本继承自Go语言即不支持继承等传统OOP而支持面向数据的类型体系以及基于组装composition和接口模式的类型体系。
先看最基本的类型定义。让我们定义一个“点”类型即Point它的有两个成员一个表示横坐标x另一个表示纵坐标y类型为整数int
凹英文版:
```wa
type Point struct {
x: int
y: int
}
func main {
p := Point{x:1, y:2}
println(p.x+p.y)
}
```
凹中文版:
```wz
《点》:
纵之数
横之数
【启】:
设p=点{横:1,纵:2}
p·x+p·y
```
这里和英文版唯一的区别就是用`《》`来表示类型定义,替代英文版的`type <name> struct`。
在struct中成员的定义和英文版一致只是用`之`来代替英文版的``,用于分隔成员名称和类型。
类型的组合模式还没有仔细研究,初步设想如下:
```wz
《三维点》:
有:点
深之数
```
这里的关键字“**有**”表示`has-a`关系,即《三维点》中包含《点》的成员。这样实际上和英文版的组合模式是一样的。
### 方法
方法是与类型绑定的函数。本质上它的运行和普通函数是一样的,但与类型绑定之后,我们可以非常自然地使用“主谓宾”的语法结构,而不是传统函数的“谓主宾”结构。
方法还有其他好处,比如可以和接口模式或组合模式结合起来,实现更复杂的类型系统。
凹英文版的方法定义如下:
```wa
func Point.Length() => int {
return math.sqrt(this.x*this.x + this.y*this.y)
}
func main {
p := Point{x:1, y:2}
println(p.Length())
}
```
和Go不同之处在于凹语言的方法定义之比普通函数在名称前多了一个前缀。`Point.Length`,表示`Length`方法是属于`Point`类型的。
这种方式和Scala、Kotlin等语言风格类似。
在方法之内,用`this`关键字表示`Point`类型的实例;即,在`p.Length()`中,`this`其实就是`p`。
凹中文版也沿用了这种方法,只是类型和方法名之间的间隔改为更适应中文的`·`,而`this`改为`此`
```wz
【点·长度】=> 数:
归于:开方:此·纵*此·纵+此·横*此·横
【启】:
设p为点{横12}
p·长度
```
### 控制流
#### if-else语句
凹英文版的`if-else`语句如下:
```go
a := 1
b := 2
if a>b {
println("bigger")
} else if a==b {
println("equals")
} else {
println("smaller")
}
```
凹中文版则是:
```wz
若1>0则
“1>0”
又若1=0则
“1==0”
否则:
“1<=0”
```
这里的关键字“**若**”表示`if`,关键字“**又若**”表示`else if`,关键字“**否则**”表示`else`,每个条件之后加了`则`关键字,以增加可读性。
#### 循环
凹英文版的循环有三种形式:
1. 三段式for循环
```go
sum := 0
for i:=0;i<10;i++ {
sum += i
}
println(sum)
```
2. while循环
```go
i := 1
for i <= 10 {
println(i)
i++
}
```
3. 无限循环
```go
for {
println("looping...")
if condition() {
break
}
}
```
第一种三段式循环,`for <初始化>;<条件>;<递进>`,三段操作分别是初始化循环变量、判断循环结束条件、以及每次执行完循环体之后做的递进更新。
第二种和第三种形式其实是这三段操作的省略而已。
凹中文版这样支持三段式:`从<初始化>,到<结束条件>,有<递进><循环体>`。例如:
```wz
设和=0
从i=0到i==10有i++:
和+=i
```
这个语法还是比较清晰的。
注意,我没有找到一个关键字可以表示“只要条件成立,就继续执行”的意思,所以只能用`到`这样的字表示“只要条件城里就结束循环”。正好和for循环的条件是反的。
没办法,这就是中英文的习惯不同。
非要和`for`循环一致的话,大概只能:
```wz
设和=0
从i=0若i<10则i++:
和+=i
```
但只读这句话,总感觉想问“这个到哪里才结束啊?”。总之还是别扭。
为了支持`for`循环的习惯用户,我还是支持了这种写法。
另外,由于用关键字替代了符号,在省略时就不如`for`循环好看了:
```wz
设i=0
设和=0
到i==0有:
和+=i
i++
```
这显然好看,所以我加了一个新关键字“直到“,可以这么写:
```wz
设i=0
设和=0
直到i==0有:
和+=i
i++
```
这就和`while`差不多了。或者更确切的说,相当于`until`语句。
至于全部省略的无限循环,只好用类似于“循环”这样的关键字了。
```wz
循环:
若xx则
停止
```
这显然不太雅观。还需要再改进。
#### switch语句
凹英文版的switch语句
```go
a := 2
switch i {
case 1:
println("one")
case 2:
println("two")
case 3, 4:
println("three and four")
case i < 10:
println("smaller than ten")
default:
println("nah")
}
```
中文版初步的想法是模仿Kotlin的`when`语句:
```wz
当i
为1“一”
为2“二”
为3“三”
否则:曰:“不中”
```
关键字`当`、`为`、`则`、`否则`分别表示`switch`、`case`、`:`和`default`。
这个语法和`when`其实也一致,因此未来可以扩充到更复杂的语句。
### 接口
凹英文版的接口:
```wa
type duck interface {
quack()
}
```
这样,包含`quack()`方法的类型都可以当做`duck`来看待。
在凹中文版中,类型定义是双书名号`《》`,因此接口的定义自然用单书名号`〈〉`,所以:
```wz
〈鸭子〉:
【嘎嘎】
```
意思就是“鸭子”这个接口,包含一个“嘎嘎”方法。这样,任何包含“嘎嘎”方法的类型都可以当做“鸭子”来看待。
注:这个特性现在还没实现。
## 展望
到现在2023年4月初为止上述的中文语法几乎都实现了但是还有一些细节需要完善。
凹中文版2023年的目标就是完全重写前端解析模块完善所有语言特性的语法与英文版做到100%对应。并作出正式的凹中文版标准语法。
届时就可以考虑给中文语法扩充更贴近中文用户使用习惯的特殊新语法了。
凹中文版的目标,不是让人人都用中文版语法、抛弃英文版语法,而是想抛砖引玉,启发所有人都来设计与开发更适合中国人的编程语言。

605
docs/wz/spec.md Normal file
View File

@ -0,0 +1,605 @@
# 语言规范
## 1 EBNF 记法
凹语言中文语法使用扩展的巴克斯-诺尔范式EBNF定义
```
Production = production_name "=" [ Expression ] "." .
Expression = Alternative { "|" Alternative } .
Alternative = Term { Term } .
Term = production_name | token [ "…" token ] | Group | Option | Repetition .
Group = "(" Expression ")" .
Option = "[" Expression "]" .
Repetition = "{" Expression "}" .
```
其中生成式由表达式构造,表达式通过术和以下操作符构造,自上而下优先级递增(低到高):
```
| 选择
() 分组
[] 可选0 或 1 次)
{} 重复0 到 n 次)
```
用小写生成式名用于标识词法标记。使用非最终Non-terminals词法标记使用驼峰记法CamelCase。而位于双引号 "" 内的即为词法标记。形式 a … b 表示把从 a 到 b 的字符集作为选择项。横向省略号 … 也在本文档中非正式地表示各种列举或简略的代码片断。单个字符 …(不同于三个字符 ...)并非凹语言本身的标记。
## 2 源文件表示
为了更好支持中文和其他语言地区的编程,凹语言源码为采用 UTF-8 编码的 Unicode 文本表示。每个码点都是不同的,例如,大写与小写的字母就是不同的字符。同时为了兼容 C 语言字符串的习惯,编译器会阻止字符 NULU+0000出现在源码文本中。此外如果源文件开头有 BOM 头部,则编译器应该忽略它。为了遵循流行编程语言的习惯,下划线字符被作为字母对待。
## 3 词法元素
### 3.1 注释
凹语言默认采用行注释,以 `//` 开头的表示行注释。注释不能从字符或字符串字面中开始,也不能在其它注释中。行注释可以视做一个换行符。
### 3.2 词符类型Token
构成凹语言的词符类型有:
- 关键字,如`若`。
- 标识符,如变量名称。
- 面值常量,如整数`123`、字符串`"abc"`、
- 运算操作符,如`+`、`-`。
- 分隔符,如`【】`、``。空白字符` `可用于分隔关键字和标识符。
凹语言程序源码首先会通过词法解析,转化为有效的词符序列,便于后续的语法解析工作。
### 3.2 基本字符
凹语言中文版的基本字符包括:
```
数字 = "0" … "9" .
16进制数字 = "0" … "9" | "a" … "f" | "A" … "F" .
字母 = "a" … "z" | "A" … "Z" | "_" | Unicode字母
Unicode字母 = /* 类别为"Letter"的Unicode字符 */ .
```
Unicode字符的“Letter”类别是Unicode标准定义的类别。凹语言根据Unicode标准来判定一个字符是否符合“Letter”类别。
### 3.3 标识符Identifier
标识符用做函数、变量、类型等程序实体的名称。一个标识符由一个或多个字母和数字组成。标识符的第一个字符必须是字母,以便于和数字面值区分。
```
标识符 = 字母 { 字母 | 数字 } .
```
标识符的示例:
```
a
实例
_obj
z123
这是_一个_很长_的_变量
```
### 3.5 关键字
关键字也是由字母组成的词符,但与标识符不同的是,它们是语言预先定义好的保留词,有特殊的语法意义,不能用于变量名称等。
凹中文版目前的关键字有:
```
引于 归于 设 之
若 则 又若 否则
从 到 有 直到
自 至 当 为
且......或
停之 续之
```
凹中文版还处于早期探索阶段,后续可能添加或修改新的关键字。
### 3.6 运算符
以下是凹中文版的运算符和与标点:
```
+ - * /
+= -= *= /=
++ -- ! &
【 】
《 》 〈 〉
[ ] { }
。 =>
```
运算符用于组成表达式,标点用于组成或分隔语句。
### 3.7 字面值
字面值是在凹语言代码中明确写出的值,有布尔值、整数、浮点数、字符串、字符几种类型。其中布尔值有`真`、`假`;整数字面值有二进制、八进制、十进制、十六进制几种表示格式;浮点数字面值有小数、科学计数法和十六进制浮点数几种形式;字符串有普通字符串和支持多行的原生字符串几种形式;字符则是有单引号包含表示单个字符。所有的字面值都是无类型的常量。
普通字符串和字符面值支持的转义符号:
```
\a U+0007 警报或铃声
\b U+0008 退格
\f U+000C 换页
\n U+000A 换行
\r U+000D 回车
\t U+0009 横向制表符
\v U+000b 纵向制表符
\\ U+005c 反斜杠
\' U+0027 单引号(仅在符文字面中有效)
\" U+0022 双引号(仅在字符串字面中有效)
```
以下是常见的字面值常量:
```
# 布尔字面值
# 整数
42
4_2
0600
0_600
-42
# 浮点数
0.
72.40
3.1415926
1_5. # == 15.0
0.15e+0_2 # == 15.0
0x1p-2 # == 0.25
0x2.p10 # == 2048.0
# 字符串
"凹语言" # UTF-8 输入的文本
`凹语言` # UTF-8 输入的原始字面文本
"\u65e5\u672c\u8a9e" # 显式的 Unicode 码点
"\U000065e5\U0000672c\U00008a9e" # 显式的 Unicode 码点
"\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e" # 显式的 UTF-8 字节
# 字符
'凹'
'a'
'ä'
'\t'
'\000'
'\007'
'\xff'
'\u12e4'
'\U00101234'
```
如果源码将两个码点表示为一个字符,例如包含着重号和字母的结合形式,凹语言会当作两个字面处理(因此不能作为字符面值)。
## 4 常量
常量由字面值或常量表达式产生,包含布尔常量、字符常量、整数常量、浮点数常量和字符串常量几种。其中字符、整数、浮点数常量统称为数值常量。
数值类型常量可表示任意精度的精确值而不受到逻辑现在,因此也就没有整数溢出和 IEEE-754 浮点数的一些限制。常量可以是有类型化的或无类型化的。字面常量、真、假某些只包含无类型化操作数的常量表达式产生的新常量结构也是无类型化的。
无类型化的常量有一个默认类型,也就是当上下文中需要类型化常量时通过隐式转换出来的类型, 例如在 `设i=0` 这种无显示类型的短变量声明中会被作为`数`int类型。
语言提提供了几个默认类型:
- `布尔`,即`真`或`假`,对应英文版的`bool`
- `字`,即单个字符,如`a`、`甲`等,对应英文版的`rune`
- `数`,整数,对应英文版的`int`,整数类型还对应了几个不同位宽的类型,如`数8`表示用8为字节存储的整数。
- `小数`,浮点数,对应英文版的`float`
- `文`,文本,即字符串,对应英文版的`string`
尽管数值型常量值域无逻辑限制,但是实现时要求编译器至少有 256bit 表示整数常量和浮点数常量,如果发生溢出则需要在编译阶段给出一个错误。
## 5 变量
凹语言中变量是内存用用于保存值的存储位置,或者叫可被取地址的值。变量允许值的集合由其类型确定,比如 `数8` 类型表示 -128 到 127 的整数集合、`布尔`表示 `真``假`的布尔值集合。
变量又分为具名和匿名两种:具名变量通过标识符引用、而匿名变量通过指针来引用。变量的静态类型在声明时确定,可以明确指定或者由初始化的值类型推导。变量的值可通过在表达式中引用变量取得。如果变量尚未赋值,其值即为其类型的零值。
零值从直观上表示内存中都是0的状态布尔类型对应 `假`、数值类型对应 0、字符串对应空字符串`""`、指针和切片对应 `空`。如果是复合类型则其组成的元素均是零值。
```
设甲之布尔 # `甲`是布尔类型
设x # x值为空类型为`万物`即interface{}
设v之*T # v值为空类型为*T
```
全部的变量组成了程序的状态,也就是所谓的上下文信息。
## 6 类型
类型不仅仅决定了值的集合,同时还定义了与该类型值特定的操作集合。已命名类型可通过类型名指定。未命名类型可通过类型字面指定,它将根据既有的类型组成新的类型。
类型的 EBNF 语法如下:
```
类型定义 = "《" 类型名称 "》" ( "=" 类型面值 | ":" 类型成员列表 "。" ) .
类型名称 = 标识符 .
类型面值 = 数组类型 | 结构类型 | 指针类型 | 函数类型 | 接口类型 | 切片类型 | 映射类型 .
类型成员列表 = 类型成员 { "," 类型成员 } .
类型成员 = 成员名称 [ "之" 类型 ] .
成员名称 = 标识符 .
```
类型的定义有两种形式,一种是类型别名,用`=`表示,另一种是结构性类型,用`:`后接成员列表。
布尔值、数值与字符串类型的实例的命名是预声明的`布尔`、`数`、`文`等。 数组、结构体、指针、函数、接口、切片和映射这些复合类型可由类型字面再进行构造。
下面是定义类型的例子:
```
// 定义一个新的类型别名名字叫“字节”它实际上是“正8”整数类型的别名
《字节》 = 正8
// 定义一个新类型别名,名称叫“缓冲区”,它实际上是一个“字类型”的定长数组,即英文版的`[1024]byte`
《缓冲区》 = [字1024]
// 定义一个新的类型别名,名字叫“字典”,它实际上是一个“文”类型的映射,即英文版的`map[string]string`
《字典》 = {文:文}
// 定义一个结构性类型,名字叫“点”,它有“横”与“纵”两个成员,分别代表横坐标和纵坐标
《点》:
横之数
纵之数
```
其中 `字节`、`缓冲区`和`字典`都是类型的别名(即不产生新类型对象),而`点`则产生新的类型。
### 5.1 布尔类型
预声明的布尔类型为 bool。布尔类型表示由预声明常量 true 和 false 所代表的布尔值的集。
### 5.2 数值类型
数值类型表示整数值和浮点数值的集合。预声明和架构无关的预声明数值类型:
```
u8 所有无符号 8 位整数集0 到 255
u16 所有无符号 16 位整数集0 到 65535
u32 所有无符号 32 位整数集0 到 4294967295
u64 所有无符号 64 位整数集0 到 18446744073709551615
i8 所有带符号 8 位整数集(-128 到 127
i16 所有带符号 16 位整数集(-32768 到 32767
i32 所有带符号 32 位整数集(-2147483648 到 2147483647
i64 所有带符号 64 位整数集(-9223372036854775808 到 9223372036854775807
f32 所有 IEEE-754 32 位浮点数集
f64 所有 IEEE-754 64 位浮点数集
byte u8 的别名
rune i32 的别名
```
比如 i32 表示用 32bit 二进制补码表示的整数值集合。
此外还有大小取决于具体实现的预声明数值类型:
```
uint 32 或 64 位
int 大小与 uint 相同
uintptr 大到足以存储指针值无解释位的无符号整数
```
但是对应凹语言来说,目前 uint/int/uintptr 在 WebAssembly 平台都是用 32bit 表示。
### 5.3 字符串类型
字符串类型为 string表示字符串值的集字符串的值为字节序列。字符串值是只读不可修改的不是绑定到某个字符串值的变量一旦被创建字符串的内容就不能更改。
可使用内建函数 `len` 获取字符串 `s` 的长度。若该字符串为常量,则其长度即为编译时常量。 字符串的字节可通过整数 `0``len(s)-1` 访问。获取这样一个元素的地址是非法的:比如通过 `&s[i]` 访问字符串的第 `i` 个字节的地址是禁止的。
### 5.4 数组类型
数组是单一类型元素的序列,其中长度也是数组类型的一部分。数组的 EBNF 语法如下:
```
ArrayType = "[" ArrayLength "]" ElementType .
ArrayLength = Expression .
ElementType = Type .
```
可使用内建函数 `len` 获取数组的长度,返回的结果一个常量。可通过整数下标 `0``len(a)-1` 访问数组的元素。数组类型总是一维的,但可组合构成多维的类型。
```
[32]byte
[2*N] struct { x, y :i32 }
[9527]*f64
[3][5]int
[2][2][2]f64 // 等价于[2]([2]([2]f64))
```
数组的长度可以使用常量表达式、或者是由初始化面值推导,数组的元素可以是数组从而可以构成多维数组。
### 5.5 切片类型
切片类型是在数组类型基础上抽象的类型,切片类型不包含底层数组的长度信息。切片类型底层是对某个数组的引用,未初始化切片的值为 nil。
可使用内建函数 `len` 获取切片的长度,返回的结果一个变量。可使用内建函数 `cap` 获取切片的容量,返回的结果一个变量。可通过整数下标 `0``len(a)-1` 访问切片的元素。切片一旦初始化,就总是引用一个包含其元素的底层数组。 因此,切片与引用同一个数组的其他切片共享存储;与此相反,不同的数组总是表示其不同的存储。
可以通过 make 内置函数创建切片(容量参赛是可选的):
```
make([]T, length)
make([]T, length, capacity)
```
类似于数组,切片总是一维的,但可组合构造多维切片对象。因为多维切片和多维数组的底层数据布局差异,其内部的切片必须单独进行初始化,但是带来的一个灵活性是不同子切片大小可以不同。
### 5.6 结构体类型
结构体和数组类似,数组采用下标来组织相同类型的值,而结构体定义命名的不同类型的元素序列。结构体类型中每一个元素都有一个名字和类型。字段名可显示地指定或通过匿名嵌入字段隐式地指定。在结构体中,字段名必须是唯一的。
```
StructType = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl = (IdentifierList ":" Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName .
Tag = string_lit .
```
下面是结构体的例子:
```
# 空结构体
struct {}
# 带 6 个字段的结构体
struct {
x, y :int
u :f32
_ :f32 # 填充
A :*[]int
F :func()
}
```
通过有类型而无显式字段名声明的字段为匿名字段,亦称为嵌入式字段或该结构体中此种类型的嵌入。 这种字段类型必须作为一个类型名 T 或一个非接口类型名的指针 *T来实现 且 T 本身不能为指针类型。未限定类型名的行为类似于字段名。
```
# 匿名字段的结构体类型
struct {
T1 # 字段名为 T1
*T2 # 字段名为 T2
P.T3 # 字段名为 T3
*P.T4 # 字段名为 T4
x, y :i32 # 字段名为 x 和 y
}
```
字段声明可后跟一个可选的字符串字面值标注:
```
struct {
x, y : f64 "" # 空标注字符串相当于没有标注
name : string "任何字符串都允许作为标注"
_ : [4]byte "这不是一个结构体字段"
}
```
标注是结构体的类型标识的一部分,未来可通过反射机制获得。
### 5.7 指针类型
指针类型表示一个指向所有给定类型变量的指针的集合,其中指向的类型称为指针的基础类型。未初始化的指针的值为 nil。
```
PointerType = "*" BaseType .
BaseType = Type .
```
下面是指针类型的例子:
```
*Point
*[4]int
```
凹语言指针和传统的 C/C++ 指针并不完全相同,目前的实现更偏向引用。
### 5.8 函数类型
凹语言函数类型表示所有带相同形参和返回类型的集合。未初始化的函数类型变量的值为 nil。
```
FunctionType = "func" Signature .
Signature = Parameters [ "=>" Result ] .
Result = Parameters | ":" Type .
Parameters = "(" [ ParameterList [ "," ] ] ")" .
ParameterList = ParameterDecl { "," ParameterDecl } .
ParameterDecl = [ IdentifierList ] ":" [ "..." ] Type .
```
在形参或结果的列表中,其名称必须都存在或都不存在。 若存在,则每个名称代表一个指定类型的项,所有在签名中的非空白名称必须是唯一的。 若不存在,则每个类型代表一个此类型的项。若恰好有一个未命名的值,它可能写作一个不加括号的类型,除此之外,形参和结果的列表总是在括号中。
函数签名中加入的最后一个形参可能有一个带 `...` 前缀的类型。 带这样形参的函数被称为变参函数,它可接受零个或多个实参。
```
func()
func(x :int) => int
func(a, _ :int, z :f32) => bool
func(a, b :int, z :f32) => (bool)
func(prefix :string, values :...int)
func(a, b :int, z :f64, opt :...any) => (success bool)
func(int, int, f64) => (f64, *[]int)
func(n :int) => func(p :*T)
```
函数的类型可以用于全局函数、闭包函数、方法值等地方。
### 5.9 接口类型
接口类型定义满足方法列表的类型结合。目前只有结构体才能定义方法。未初始化的接口类型变量的值为 nil。
```
InterfaceType = "interface" "{" { ( MethodSpec | InterfaceTypeName ) ";" } "}" .
MethodSpec = MethodName Signature .
MethodName = identifier .
InterfaceTypeName = TypeName .
```
下面是一个接口类型定义的方法集合:
```
# 一个简单的 File 接口
interface {
Read(b :[]byte) => (n :int, err :error)
Write(b :[]byte) => (n :int, err :error)
Close()
}
```
如果 T 类型有着接口定义的方法,那么就表示实现了接口:
```
func T.Read(p :[]byte) => (n :int, err :error)
func T.Write(p :[]byte) => (n :int, err :error)
func T.Close() error
```
其中没有定义方法集的 `interface{}` 接口可以包含任何类型的值,同时它有一个 `any` 别名。
### 5.10 map类型
map 是一个同种类型元素的无序组,该类型称为元素类型 映射通过另一类型唯一的键集索引,该类型称为键类型。未初始化的映射值为 nil。
```
MapType = "map" "[" KeyType "]" ElementType .
KeyType = Type .
```
比较操作符 `==``!=` 必须由键类型的操作数完全定义;因此键类型不能是函数、映射或切片。若该键类型为接口类型,这些比较运算符必须由动态键值定义;失败将导致一个异常.
同样通过 make 内置函数创建一个 map
```
make(map[string]int)
make(map[string]int, 100)
```
make创建map时第二个是一个可选的容量估计参数。
## 6 类型与值的性质
## 6.1 类型标识
若两个已命名类型的类型名源自相同的类型实现,它们就是相同的。一个已命名类型和一个未命名类型总不相同。若两个未命名类型其相应的类型字面相同,那么它们的类型相同,即它们的字面结构是否相同且其相应的组件类型是否相同。细节详述:
- 若两个数组类型其元素类型相同且长度相同,那么它们的类型相同。
- 若两个切片类型其元素类型相同,那么它们的类型相同。
- 若两个结构体类型其字段序列相同、相应字段名相同、类型相同、标注相同,那么它们的类型相同。两个匿名字段根据其名字被判定是否相同。
- 若两个指针类型其基础类型相同,那么它们的类型相同。
- 若两个函数类型其形参个数相同、返回值相同、相应形参类型相同、返回值类型相同,那么它们的类型相同。形参和返回值名无需匹配。
- 若两个接口类型其方法集相同、名字相同、函数类型相同,那么它们的类型相同。出自不同包的小写方法名总不相同。两接口类型是否相同与方法的次序无关。
- 若两个map类型其键值类型相同那么它们的类型相同。
若两个类型非相同即为不同。
## 6.2 可赋值性
在下列情况下,值 x 可赋予类型为 T 的变量:
- 当 x 的类型和 T 相同时。
- 当 x 的类型 V 和 T 有相同的 底层类型 且在 V 或 T 中至少有一个不是已命名类型时。
- 当 T 为接口类型且 x 实现了 T 时。
- 当 x 为预声明标识符 nil 且 T 为指针、函数、切片、映射、通道或接口类型时。
- 当 x 为无类型化,可通过类型 T 的值来表示的 常量时。
任何类型都可赋予下划线表示的空白标识符.
## 6.3 可表示性
若满足以下条件,则常量 x 可表示为 T 类型的值:
- x 在由 T 所确定的值的集合中。
- T 为浮点类型且 x 可被舍入到 T 的精度而不会溢出。
下面是一个例子:
```
x T x 可表示为一个 T 类型的值,因为
'a' byte 97 属于 byte 值的集合
97 rune rune 是 int32 的别名,且 97 属于 32 位整数值的集合
"foo" string "foo" 属于 string 值的集合
1024 int16 1024 属于 16 位整数的集合
42.0 byte 42 属于无符号 8 位整数的集合
1e10 u64 10000000000 属于 64 位无符号整数的集合
2.718281828459045 f32 2.718281828459045 舍入到 2.7182817,它属于 f32 值的集合
-1e-1000 f64 -1e-1000 舍入到 IEEE -0.0,它进一步简化为 0.0
0i int 0 是一个整数值
x T x 无法表示为一个 T 类型的值,因为
0 bool 0 不属于布尔值的集合
'a' string 'a' 是一个 rune它不属于 string 值的集合
1024 byte 1024 不属于无符号 8 位整数的集合
-1 uint16 -1 不属于 16 位无符号整数的集合
1.1 int 1.1 不是一个整数值
1e1000 f64 1e1000 舍入后溢出到 IEEE +Inf
```
## 7 代码块
凹语言代码块为一对大括号括住的,可能为空的一系列声明和语句。
```
Block = "{" StatementList "}" .
StatementList = { Statement ";" } .
```
除显式源码块外,还有一些隐式块:
- 全域块包含所有的 凹语言 源码文本。
- 每个包都有包含其所有 凹语言 源码文本的包块。
- 每个文件都有包含其所有 凹语言 源码文本的文件块。
- 每个 if、for 和 switch 语句都被视为处于其自身的隐式块中。
- 每个 switch 语句中的子句其行为如同隐式块。
块可嵌套并会影响作用域。
## 8 声明与作用域
凹语言中声明可将非空白标识符绑定到一个常量、类型、变量、函数、标签或包。在程序中,每个标识符都必须被声明才能被使用。同一标识符不能在同一代码块中声明两次,且在文件与包代码块中不能同时声明。
下划线表示的空白标识符可像其它标识符一样在声明中使用,但它不会引入绑定被视作未声明的。在包块中,标识符 init 仅能用作 init 函数声明,且与空白标识符一样不会引入新的绑定。
```
Declaration = ConstDecl | TypeDecl | VarDecl .
TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
```
已声明标识符的作用域即为该标识符所表示的具名常量、类型、变量、函数、标签或包在源文本中的作用范围。
凹语言 使用块表示词法作用域:
1. 预声明标识符的作用域为全域块。
1. 即在任何函数之外的顶级声明的表示常量、类型、变量或函数的标识符其作用域为该包块。
1. 已导入包的包名作用域为仅包含该导入声明的文件块。
1. 表示方法接收器 this、函数形参或返回值变量的标识符其作用域为该函数体。
1. 在函数中声明为常量或变量的标识符,其作用域始于该函数中具体常量实现或变量实现的结尾,止于最内部包含块的结尾。
1. 在函数中声明为类型的标识符,其作用域始于该函数中具体类型实现的标识符,止于最内部包含块的结尾。
在块中短声明的标识符可在其内部块中重新声明。
## 8.1 标签作用域
## 8.2 空白标识符
## 9 表达式
## 10 语句
## 11 包结构
## 12 初始化和执行顺序

7
go.mod
View File

@ -1,10 +1,11 @@
// @2019
module github.com/wa-lang/wa
module wa-lang.org/wa
go 1.17
require (
github.com/tetratelabs/wazero v1.0.0-pre.3
github.com/wa-lang/wabt-go v1.1.0
github.com/BurntSushi/toml v1.3.2
wa-lang.org/wabt-go v1.3.0
wa-lang.org/wazero v1.0.1
)

14
go.sum
View File

@ -1,4 +1,10 @@
github.com/tetratelabs/wazero v1.0.0-pre.3 h1:Z5fbogMUGcERzaQb9mQU8+yJSy0bVvv2ce3dfR4wcZg=
github.com/tetratelabs/wazero v1.0.0-pre.3/go.mod h1:M8UDNECGm/HVjOfq0EOe4QfCY9Les1eq54IChMLETbc=
github.com/wa-lang/wabt-go v1.1.0 h1:0ois7H69M+6lJhjqU/3c5HxTGeQjwTW0Ncj+SLEW96o=
github.com/wa-lang/wabt-go v1.1.0/go.mod h1:I/qIi3rHMN4ECgmZ8FzYwpNr2KfLs4TiXuTi7Ql7H3g=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/tetratelabs/wazero v1.0.0-pre.4 h1:RBJQT5OzmORkSp6MmZDWoFEr0zXjk4pmvMKAdeUnsaI=
github.com/tetratelabs/wazero v1.0.0-pre.4/go.mod h1:u8wrFmpdrykiFK0DFPiFm5a4+0RzsdmXYVtijBKqUVo=
wa-lang.org/wabt-go v1.2.3 h1:xwGW3+IrCMAPDx+ngQFx7vl0xBc1vuooRNql7i2yCiA=
wa-lang.org/wabt-go v1.2.3/go.mod h1:v4fKY/p4oMiKwQ2S2aC/wOXvJ2bk2MgtLmwK0TKTNx0=
wa-lang.org/wabt-go v1.3.0 h1:7oSrr80hGlf9G6wwf2pQQ1NXbeqBxEk3D3GDWwbYmVA=
wa-lang.org/wabt-go v1.3.0/go.mod h1:v4fKY/p4oMiKwQ2S2aC/wOXvJ2bk2MgtLmwK0TKTNx0=
wa-lang.org/wazero v1.0.1 h1:6o6M2o6TP0c6b1+jJtfFaAJQGBIk8HrDegIGzrtwmGc=
wa-lang.org/wazero v1.0.1/go.mod h1:r1lGhhlgAnh5eZyNHe/dslT0LF7aY3qZGJWCbxRqf3E=

View File

@ -1,14 +0,0 @@
# 版权 @2019 凹语言 作者。保留所有权利。
import "fmt"
fn main {
println("你好,凹语言!")
println(add(40, 2))
fmt.Println(1+1)
}
fn add(a: i32, b: i32) => i32 {
return a+b
}

9
internal/3rdparty/jsonrpc2/LICENSE vendored Normal file
View File

@ -0,0 +1,9 @@
Copyright (c) 2016 Sourcegraph Inc
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

12
internal/3rdparty/jsonrpc2/README.md vendored Normal file
View File

@ -0,0 +1,12 @@
# jsonrpc2: JSON-RPC 2.0 implementation for Go [![Build Status](https://travis-ci.org/sourcegraph/jsonrpc2.svg)](https://travis-ci.org/sourcegraph/jsonrpc2) [![Sourcegraph](https://sourcegraph.com/github.com/sourcegraph/jsonrpc2/-/badge.svg)](https://sourcegraph.com/github.com/sourcegraph/jsonrpc2?badge) [![GoDoc](https://godoc.org/github.com/sourcegraph/jsonrpc2?status.svg)](https://godoc.org/github.com/sourcegraph/jsonrpc2)
Package jsonrpc2 provides a [Go](https://golang.org) implementation of [JSON-RPC 2.0](http://www.jsonrpc.org/specification).
This package is **experimental** until further notice.
[**Open the code in Sourcegraph**](https://sourcegraph.com/github.com/sourcegraph/jsonrpc2)
## Known issues
* Batch requests and responses are not yet supported.

17
internal/3rdparty/jsonrpc2/async.go vendored Normal file
View File

@ -0,0 +1,17 @@
package jsonrpc2
import "context"
// AsyncHandler wraps a Handler such that each request is handled in its own
// goroutine. It is a convenience wrapper.
func AsyncHandler(h Handler) Handler {
return asyncHandler{h}
}
type asyncHandler struct {
Handler
}
func (h asyncHandler) Handle(ctx context.Context, conn *Conn, req *Request) {
go h.Handler.Handle(ctx, conn, req)
}

48
internal/3rdparty/jsonrpc2/call_opt.go vendored Normal file
View File

@ -0,0 +1,48 @@
package jsonrpc2
// CallOption is an option that can be provided to (*Conn).Call to
// configure custom behavior. See Meta.
type CallOption interface {
apply(r *Request) error
}
type callOptionFunc func(r *Request) error
func (c callOptionFunc) apply(r *Request) error { return c(r) }
// Meta returns a call option which attaches the given meta object to
// the JSON-RPC 2.0 request (this is a Sourcegraph extension to JSON
// RPC 2.0 for carrying metadata).
func Meta(meta interface{}) CallOption {
return callOptionFunc(func(r *Request) error {
return r.SetMeta(meta)
})
}
// ExtraField returns a call option which attaches the given name/value pair to
// the JSON-RPC 2.0 request. This can be used to add arbitrary extensions to
// JSON RPC 2.0.
func ExtraField(name string, value interface{}) CallOption {
return callOptionFunc(func(r *Request) error {
return r.SetExtraField(name, value)
})
}
// PickID returns a call option which sets the ID on a request. Care must be
// taken to ensure there are no conflicts with any previously picked ID, nor
// with the default sequence ID.
func PickID(id ID) CallOption {
return callOptionFunc(func(r *Request) error {
r.ID = id
return nil
})
}
// StringID returns a call option that instructs the request ID to be set as a
// string.
func StringID() CallOption {
return callOptionFunc(func(r *Request) error {
r.ID.IsString = true
return nil
})
}

471
internal/3rdparty/jsonrpc2/conn.go vendored Normal file
View File

@ -0,0 +1,471 @@
package jsonrpc2
import (
"bytes"
"context"
"encoding/json"
"errors"
"io"
"log"
"os"
"strconv"
"sync"
)
// Conn is a JSON-RPC client/server connection. The JSON-RPC protocol
// is symmetric, so a Conn runs on both ends of a client-server
// connection.
type Conn struct {
stream ObjectStream
h Handler
mu sync.Mutex
closed bool
seq uint64
pending map[ID]*call
sending sync.Mutex
disconnect chan struct{}
logger Logger
// Set by ConnOpt funcs.
onRecv []func(*Request, *Response)
onSend []func(*Request, *Response)
}
var _ JSONRPC2 = (*Conn)(nil)
// NewConn creates a new JSON-RPC client/server connection using the
// given ReadWriteCloser (typically a TCP connection or stdio). The
// JSON-RPC protocol is symmetric, so a Conn runs on both ends of a
// client-server connection.
//
// NewClient consumes conn, so you should call Close on the returned
// client not on the given conn.
func NewConn(ctx context.Context, stream ObjectStream, h Handler, opts ...ConnOpt) *Conn {
c := &Conn{
stream: stream,
h: h,
pending: map[ID]*call{},
disconnect: make(chan struct{}),
logger: log.New(os.Stderr, "", log.LstdFlags),
}
for _, opt := range opts {
if opt == nil {
continue
}
opt(c)
}
go c.readMessages(ctx)
return c
}
// Close closes the JSON-RPC connection. The connection may not be
// used after it has been closed.
func (c *Conn) Close() error {
return c.close(nil)
}
// Call initiates a JSON-RPC call using the specified method and params, and
// waits for the response. If the response is successful, its result is stored
// in result (a pointer to a value that can be JSON-unmarshaled into);
// otherwise, a non-nil error is returned. See DispatchCall for more details.
func (c *Conn) Call(ctx context.Context, method string, params, result interface{}, opts ...CallOption) error {
call, err := c.DispatchCall(ctx, method, params, opts...)
if err != nil {
return err
}
return call.Wait(ctx, result)
}
// DisconnectNotify returns a channel that is closed when the
// underlying connection is disconnected.
func (c *Conn) DisconnectNotify() <-chan struct{} {
return c.disconnect
}
// DispatchCall dispatches a JSON-RPC call using the specified method and
// params, and returns a call proxy or an error. Call Wait() on the returned
// proxy to receive the response. Only use this function if you need to do work
// after dispatching the request, otherwise use Call.
//
// The params member is omitted from the JSON-RPC request if the given params is
// nil. Use json.RawMessage("null") to send a JSON-RPC request with its params
// member set to null.
func (c *Conn) DispatchCall(ctx context.Context, method string, params interface{}, opts ...CallOption) (Waiter, error) {
req := &Request{Method: method}
for _, opt := range opts {
if opt == nil {
continue
}
if err := opt.apply(req); err != nil {
return Waiter{}, err
}
}
if params != nil {
if err := req.SetParams(params); err != nil {
return Waiter{}, err
}
}
call, err := c.send(ctx, &anyMessage{request: req}, true)
if err != nil {
return Waiter{}, err
}
return Waiter{call: call}, nil
}
// Notify is like Call, but it returns when the notification request is sent
// (without waiting for a response, because JSON-RPC notifications do not have
// responses).
//
// The params member is omitted from the JSON-RPC request if the given params is
// nil. Use json.RawMessage("null") to send a JSON-RPC request with its params
// member set to null.
func (c *Conn) Notify(ctx context.Context, method string, params interface{}, opts ...CallOption) error {
req := &Request{Method: method, Notif: true}
for _, opt := range opts {
if opt == nil {
continue
}
if err := opt.apply(req); err != nil {
return err
}
}
if params != nil {
if err := req.SetParams(params); err != nil {
return err
}
}
_, err := c.send(ctx, &anyMessage{request: req}, false)
return err
}
// Reply sends a successful response with a result.
func (c *Conn) Reply(ctx context.Context, id ID, result interface{}) error {
resp := &Response{ID: id}
if err := resp.SetResult(result); err != nil {
return err
}
_, err := c.send(ctx, &anyMessage{response: resp}, false)
return err
}
// ReplyWithError sends a response with an error.
func (c *Conn) ReplyWithError(ctx context.Context, id ID, respErr *Error) error {
_, err := c.send(ctx, &anyMessage{response: &Response{ID: id, Error: respErr}}, false)
return err
}
// SendResponse sends resp to the peer. It is lower level than (*Conn).Reply.
func (c *Conn) SendResponse(ctx context.Context, resp *Response) error {
_, err := c.send(ctx, &anyMessage{response: resp}, false)
return err
}
func (c *Conn) close(cause error) error {
c.sending.Lock()
c.mu.Lock()
defer c.sending.Unlock()
defer c.mu.Unlock()
if c.closed {
return ErrClosed
}
for _, call := range c.pending {
close(call.done)
}
if cause != nil && cause != io.EOF && cause != io.ErrUnexpectedEOF {
c.logger.Printf("jsonrpc2: protocol error: %v\n", cause)
}
close(c.disconnect)
c.closed = true
return c.stream.Close()
}
func (c *Conn) readMessages(ctx context.Context) {
var err error
for err == nil {
var m anyMessage
err = c.stream.ReadObject(&m)
if err != nil {
break
}
switch {
case m.request != nil:
for _, onRecv := range c.onRecv {
onRecv(m.request, nil)
}
c.h.Handle(ctx, c, m.request)
case m.response != nil:
resp := m.response
if resp != nil {
id := resp.ID
c.mu.Lock()
call := c.pending[id]
delete(c.pending, id)
c.mu.Unlock()
if call != nil {
call.response = resp
}
if len(c.onRecv) > 0 {
var req *Request
if call != nil {
req = call.request
}
for _, onRecv := range c.onRecv {
onRecv(req, resp)
}
}
switch {
case call == nil:
c.logger.Printf("jsonrpc2: ignoring response #%s with no corresponding request\n", id)
case resp.Error != nil:
call.done <- resp.Error
close(call.done)
default:
call.done <- nil
close(call.done)
}
}
}
}
c.close(err)
}
func (c *Conn) send(_ context.Context, m *anyMessage, wait bool) (cc *call, err error) {
c.sending.Lock()
defer c.sending.Unlock()
// m.request.ID could be changed, so we store a copy to correctly
// clean up pending
var id ID
c.mu.Lock()
if c.closed {
c.mu.Unlock()
return nil, ErrClosed
}
// Assign a default id if not set
if m.request != nil && wait {
cc = &call{request: m.request, seq: c.seq, done: make(chan error, 1)}
isIDUnset := len(m.request.ID.Str) == 0 && m.request.ID.Num == 0
if isIDUnset {
if m.request.ID.IsString {
m.request.ID.Str = strconv.FormatUint(c.seq, 10)
} else {
m.request.ID.Num = c.seq
}
}
c.seq++
}
c.mu.Unlock()
if len(c.onSend) > 0 {
var (
req *Request
resp *Response
)
switch {
case m.request != nil:
req = m.request
case m.response != nil:
resp = m.response
}
for _, onSend := range c.onSend {
onSend(req, resp)
}
}
// Store requests so we can later associate them with incoming
// responses.
if m.request != nil && wait {
c.mu.Lock()
id = m.request.ID
c.pending[id] = cc
c.mu.Unlock()
}
// From here on, if we fail to send this, then we need to remove
// this from the pending map so we don't block on it or pile up
// pending entries for unsent messages.
defer func() {
if err != nil {
if cc != nil {
c.mu.Lock()
delete(c.pending, id)
c.mu.Unlock()
}
}
}()
if err := c.stream.WriteObject(m); err != nil {
return nil, err
}
return cc, nil
}
// Waiter proxies an ongoing JSON-RPC call.
type Waiter struct {
*call
}
// Wait for the result of an ongoing JSON-RPC call. If the response
// is successful, its result is stored in result (a pointer to a
// value that can be JSON-unmarshaled into); otherwise, a non-nil
// error is returned.
func (w Waiter) Wait(ctx context.Context, result interface{}) error {
select {
case err, ok := <-w.call.done:
if !ok {
err = ErrClosed
}
if err != nil {
return err
}
if result != nil {
if w.call.response.Result == nil {
w.call.response.Result = &jsonNull
}
if err := json.Unmarshal(*w.call.response.Result, result); err != nil {
return err
}
}
return nil
case <-ctx.Done():
return ctx.Err()
}
}
// call represents a JSON-RPC call over its entire lifecycle.
type call struct {
request *Request
response *Response
seq uint64 // the seq of the request
done chan error
}
// anyMessage represents either a JSON Request or Response.
type anyMessage struct {
request *Request
response *Response
}
func (m anyMessage) MarshalJSON() ([]byte, error) {
var v interface{}
switch {
case m.request != nil && m.response == nil:
v = m.request
case m.request == nil && m.response != nil:
v = m.response
}
if v != nil {
return json.Marshal(v)
}
return nil, errors.New("jsonrpc2: message must have exactly one of the request or response fields set")
}
func (m *anyMessage) UnmarshalJSON(data []byte) error {
// The presence of these fields distinguishes between the 2
// message types.
type msg struct {
ID interface{} `json:"id"`
Method *string `json:"method"`
Result anyValueWithExplicitNull `json:"result"`
Error interface{} `json:"error"`
}
var isRequest, isResponse bool
checkType := func(m *msg) error {
mIsRequest := m.Method != nil
mIsResponse := m.Result.null || m.Result.value != nil || m.Error != nil
if (!mIsRequest && !mIsResponse) || (mIsRequest && mIsResponse) {
return errors.New("jsonrpc2: unable to determine message type (request or response)")
}
if (mIsRequest && isResponse) || (mIsResponse && isRequest) {
return errors.New("jsonrpc2: batch message type mismatch (must be all requests or all responses)")
}
isRequest = mIsRequest
isResponse = mIsResponse
return nil
}
if isArray := len(data) > 0 && data[0] == '['; isArray {
var msgs []msg
if err := json.Unmarshal(data, &msgs); err != nil {
return err
}
if len(msgs) == 0 {
return errors.New("jsonrpc2: invalid empty batch")
}
for i := range msgs {
if err := checkType(&msg{
ID: msgs[i].ID,
Method: msgs[i].Method,
Result: msgs[i].Result,
Error: msgs[i].Error,
}); err != nil {
return err
}
}
} else {
var m msg
if err := json.Unmarshal(data, &m); err != nil {
return err
}
if err := checkType(&m); err != nil {
return err
}
}
var v interface{}
switch {
case isRequest && !isResponse:
v = &m.request
case !isRequest && isResponse:
v = &m.response
}
if err := json.Unmarshal(data, v); err != nil {
return err
}
if !isRequest && isResponse && m.response.Error == nil && m.response.Result == nil {
m.response.Result = &jsonNull
}
return nil
}
// anyValueWithExplicitNull is used to distinguish {} from
// {"result":null} by anyMessage's JSON unmarshaler.
type anyValueWithExplicitNull struct {
null bool // JSON "null"
value interface{}
}
func (v anyValueWithExplicitNull) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *anyValueWithExplicitNull) UnmarshalJSON(data []byte) error {
data = bytes.TrimSpace(data)
if string(data) == "null" {
*v = anyValueWithExplicitNull{null: true}
return nil
}
*v = anyValueWithExplicitNull{}
return json.Unmarshal(data, &v.value)
}

111
internal/3rdparty/jsonrpc2/conn_opt.go vendored Normal file
View File

@ -0,0 +1,111 @@
package jsonrpc2
import (
"encoding/json"
"sync"
)
// Logger interface implements one method - Printf.
// You can use the stdlib logger *log.Logger
type Logger interface {
Printf(format string, v ...interface{})
}
// ConnOpt is the type of function that can be passed to NewConn to
// customize the Conn before it is created.
type ConnOpt func(*Conn)
// OnRecv causes all requests received on conn to invoke f(req, nil)
// and all responses to invoke f(req, resp),
func OnRecv(f func(*Request, *Response)) ConnOpt {
return func(c *Conn) { c.onRecv = append(c.onRecv, f) }
}
// OnSend causes all requests sent on conn to invoke f(req, nil) and
// all responses to invoke f(nil, resp),
func OnSend(f func(*Request, *Response)) ConnOpt {
return func(c *Conn) { c.onSend = append(c.onSend, f) }
}
// LogMessages causes all messages sent and received on conn to be
// logged using the provided logger.
func LogMessages(logger Logger) ConnOpt {
return func(c *Conn) {
// Remember reqs we have received so we can helpfully show the
// request method in OnSend for responses.
var (
mu sync.Mutex
reqMethods = map[ID]string{}
)
// Set custom logger from provided input
c.logger = logger
OnRecv(func(req *Request, resp *Response) {
switch {
case req != nil:
mu.Lock()
reqMethods[req.ID] = req.Method
mu.Unlock()
params, _ := json.Marshal(req.Params)
if req.Notif {
logger.Printf("jsonrpc2: --> notif: %s: %s\n", req.Method, params)
} else {
logger.Printf("jsonrpc2: --> request #%s: %s: %s\n", req.ID, req.Method, params)
}
case resp != nil:
var method string
if req != nil {
method = req.Method
} else {
method = "(no matching request)"
}
switch {
case resp.Result != nil:
result, _ := json.Marshal(resp.Result)
logger.Printf("jsonrpc2: --> result #%s: %s: %s\n", resp.ID, method, result)
case resp.Error != nil:
err, _ := json.Marshal(resp.Error)
logger.Printf("jsonrpc2: --> error #%s: %s: %s\n", resp.ID, method, err)
}
}
})(c)
OnSend(func(req *Request, resp *Response) {
switch {
case req != nil:
params, _ := json.Marshal(req.Params)
if req.Notif {
logger.Printf("jsonrpc2: <-- notif: %s: %s\n", req.Method, params)
} else {
logger.Printf("jsonrpc2: <-- request #%s: %s: %s\n", req.ID, req.Method, params)
}
case resp != nil:
mu.Lock()
method := reqMethods[resp.ID]
delete(reqMethods, resp.ID)
mu.Unlock()
if method == "" {
method = "(no previous request)"
}
if resp.Result != nil {
result, _ := json.Marshal(resp.Result)
logger.Printf("jsonrpc2: <-- result #%s: %s: %s\n", resp.ID, method, result)
} else {
err, _ := json.Marshal(resp.Error)
logger.Printf("jsonrpc2: <-- error #%s: %s: %s\n", resp.ID, method, err)
}
}
})(c)
}
}
// SetLogger sets the logger for the connection.
func SetLogger(logger Logger) ConnOpt {
return func(c *Conn) {
c.logger = logger
}
}

View File

@ -0,0 +1,64 @@
package jsonrpc2
import (
"context"
)
// HandlerWithError implements Handler by calling the func for each
// request and handling returned errors and results.
func HandlerWithError(handleFunc func(context.Context, *Conn, *Request) (result interface{}, err error)) *HandlerWithErrorConfigurer {
return &HandlerWithErrorConfigurer{handleFunc: handleFunc}
}
// HandlerWithErrorConfigurer is a handler created by HandlerWithError.
type HandlerWithErrorConfigurer struct {
handleFunc func(context.Context, *Conn, *Request) (result interface{}, err error)
suppressErrClosed bool
}
// Handle implements Handler.
func (h *HandlerWithErrorConfigurer) Handle(ctx context.Context, conn *Conn, req *Request) {
result, err := h.handleFunc(ctx, conn, req)
if req.Notif {
if err != nil {
conn.logger.Printf("jsonrpc2 handler: notification %q handling error: %v\n", req.Method, err)
}
return
}
resp := &Response{ID: req.ID}
if err == nil {
err = resp.SetResult(result)
}
if err != nil {
if e, ok := err.(*Error); ok {
resp.Error = e
} else {
resp.Error = &Error{Message: err.Error()}
}
}
if !req.Notif {
if err := conn.SendResponse(ctx, resp); err != nil {
if err != ErrClosed || !h.suppressErrClosed {
conn.logger.Printf("jsonrpc2 handler: sending response %s: %v\n", resp.ID, err)
}
}
}
}
// SuppressErrClosed makes the handler suppress jsonrpc2.ErrClosed errors from
// being logged. The original handler `h` is returned.
//
// This is optional because only in some cases is this behavior desired. For
// example, a handler that serves end-user connections may not want to log
// ErrClosed because it just indicates the end-user connection has gone away
// for any reason (they could have lost wifi connection, are no longer
// interested in the request and closed the connection, etc) and as such it
// would be log spam, whereas a handler that serves internal connections would
// never expect connections to go away unexpectedly (which could indicate
// service degradation, etc) and as such ErrClosed should always be logged.
func (h *HandlerWithErrorConfigurer) SuppressErrClosed() Handler {
h.suppressErrClosed = true
return h
}

119
internal/3rdparty/jsonrpc2/jsonrpc2.go vendored Normal file
View File

@ -0,0 +1,119 @@
// Package jsonrpc2 provides a client and server implementation of
// [JSON-RPC 2.0](http://www.jsonrpc.org/specification).
package jsonrpc2
import (
"context"
"encoding/json"
"errors"
"fmt"
"strconv"
)
// JSONRPC2 describes an interface for issuing requests that speak the
// JSON-RPC 2 protocol. It isn't really necessary for this package
// itself, but is useful for external users that use the interface as
// an API boundary.
type JSONRPC2 interface {
// Call issues a standard request (http://www.jsonrpc.org/specification#request_object).
Call(ctx context.Context, method string, params, result interface{}, opt ...CallOption) error
// Notify issues a notification request (http://www.jsonrpc.org/specification#notification).
Notify(ctx context.Context, method string, params interface{}, opt ...CallOption) error
// Close closes the underlying connection, if it exists.
Close() error
}
// Error represents a JSON-RPC response error.
type Error struct {
Code int64 `json:"code"`
Message string `json:"message"`
Data *json.RawMessage `json:"data,omitempty"`
}
// SetError sets e.Data to the JSON encoding of v. If JSON
// marshaling fails, it panics.
func (e *Error) SetError(v interface{}) {
b, err := json.Marshal(v)
if err != nil {
panic("Error.SetData: " + err.Error())
}
e.Data = (*json.RawMessage)(&b)
}
// Error implements the Go error interface.
func (e *Error) Error() string {
return fmt.Sprintf("jsonrpc2: code %v message: %s", e.Code, e.Message)
}
// Errors defined in the JSON-RPC spec. See
// http://www.jsonrpc.org/specification#error_object.
const (
CodeParseError = -32700
CodeInvalidRequest = -32600
CodeMethodNotFound = -32601
CodeInvalidParams = -32602
CodeInternalError = -32603
)
// Handler handles JSON-RPC requests and notifications.
type Handler interface {
// Handle is called to handle a request. No other requests are handled
// until it returns. If you do not require strict ordering behavior
// of received RPCs, it is suggested to wrap your handler in
// AsyncHandler.
Handle(context.Context, *Conn, *Request)
}
// ID represents a JSON-RPC 2.0 request ID, which may be either a
// string or number (or null, which is unsupported).
type ID struct {
// At most one of Num or Str may be nonzero. If both are zero
// valued, then IsNum specifies which field's value is to be used
// as the ID.
Num uint64
Str string
// IsString controls whether the Num or Str field's value should be
// used as the ID, when both are zero valued. It must always be
// set to true if the request ID is a string.
IsString bool
}
func (id ID) String() string {
if id.IsString {
return strconv.Quote(id.Str)
}
return strconv.FormatUint(id.Num, 10)
}
// MarshalJSON implements json.Marshaler.
func (id ID) MarshalJSON() ([]byte, error) {
if id.IsString {
return json.Marshal(id.Str)
}
return json.Marshal(id.Num)
}
// UnmarshalJSON implements json.Unmarshaler.
func (id *ID) UnmarshalJSON(data []byte) error {
// Support both uint64 and string IDs.
var v uint64
if err := json.Unmarshal(data, &v); err == nil {
*id = ID{Num: v}
return nil
}
var v2 string
if err := json.Unmarshal(data, &v2); err != nil {
return err
}
*id = ID{Str: v2, IsString: true}
return nil
}
// ErrClosed indicates that the JSON-RPC connection is closed (or in
// the process of closing).
var ErrClosed = errors.New("jsonrpc2: connection is closed")
var jsonNull = json.RawMessage("null")

174
internal/3rdparty/jsonrpc2/request.go vendored Normal file
View File

@ -0,0 +1,174 @@
package jsonrpc2
import (
"bytes"
"encoding/json"
"errors"
"fmt"
)
// Request represents a JSON-RPC request or
// notification. See
// http://www.jsonrpc.org/specification#request_object and
// http://www.jsonrpc.org/specification#notification.
type Request struct {
Method string `json:"method"`
Params *json.RawMessage `json:"params,omitempty"`
ID ID `json:"id"`
Notif bool `json:"-"`
// Meta optionally provides metadata to include in the request.
//
// NOTE: It is not part of spec. However, it is useful for propagating
// tracing context, etc.
Meta *json.RawMessage `json:"meta,omitempty"`
// ExtraFields optionally adds fields to the root of the JSON-RPC request.
//
// NOTE: It is not part of the spec, but there are other protocols based on
// JSON-RPC 2 that require it.
ExtraFields []RequestField `json:"-"`
}
// MarshalJSON implements json.Marshaler and adds the "jsonrpc":"2.0"
// property.
func (r Request) MarshalJSON() ([]byte, error) {
r2 := map[string]interface{}{
"jsonrpc": "2.0",
"method": r.Method,
}
for _, field := range r.ExtraFields {
r2[field.Name] = field.Value
}
if !r.Notif {
r2["id"] = &r.ID
}
if r.Params != nil {
r2["params"] = r.Params
}
if r.Meta != nil {
r2["meta"] = r.Meta
}
return json.Marshal(r2)
}
// UnmarshalJSON implements json.Unmarshaler.
func (r *Request) UnmarshalJSON(data []byte) error {
r2 := make(map[string]interface{})
// Detect if the "params" or "meta" fields are JSON "null" or just not
// present by seeing if the field gets overwritten to nil.
emptyParams := &json.RawMessage{}
r2["params"] = emptyParams
emptyMeta := &json.RawMessage{}
r2["meta"] = emptyMeta
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.UseNumber()
if err := decoder.Decode(&r2); err != nil {
return err
}
var ok bool
r.Method, ok = r2["method"].(string)
if !ok {
return errors.New("missing method field")
}
switch {
case r2["params"] == nil:
r.Params = &jsonNull
case r2["params"] == emptyParams:
r.Params = nil
default:
b, err := json.Marshal(r2["params"])
if err != nil {
return fmt.Errorf("failed to marshal params: %w", err)
}
r.Params = (*json.RawMessage)(&b)
}
switch {
case r2["meta"] == nil:
r.Meta = &jsonNull
case r2["meta"] == emptyMeta:
r.Meta = nil
default:
b, err := json.Marshal(r2["meta"])
if err != nil {
return fmt.Errorf("failed to marshal Meta: %w", err)
}
r.Meta = (*json.RawMessage)(&b)
}
switch rawID := r2["id"].(type) {
case nil:
r.ID = ID{}
r.Notif = true
case string:
r.ID = ID{Str: rawID, IsString: true}
r.Notif = false
case json.Number:
id, err := rawID.Int64()
if err != nil {
return fmt.Errorf("failed to unmarshal ID: %w", err)
}
r.ID = ID{Num: uint64(id)}
r.Notif = false
default:
return fmt.Errorf("unexpected ID type: %T", rawID)
}
// Clear the extra fields before populating them again.
r.ExtraFields = nil
for name, value := range r2 {
switch name {
case "id", "jsonrpc", "meta", "method", "params":
continue
}
r.ExtraFields = append(r.ExtraFields, RequestField{
Name: name,
Value: value,
})
}
return nil
}
// SetParams sets r.Params to the JSON encoding of v. If JSON
// marshaling fails, it returns an error.
func (r *Request) SetParams(v interface{}) error {
b, err := json.Marshal(v)
if err != nil {
return err
}
r.Params = (*json.RawMessage)(&b)
return nil
}
// SetMeta sets r.Meta to the JSON encoding of v. If JSON
// marshaling fails, it returns an error.
func (r *Request) SetMeta(v interface{}) error {
b, err := json.Marshal(v)
if err != nil {
return err
}
r.Meta = (*json.RawMessage)(&b)
return nil
}
// SetExtraField adds an entry to r.ExtraFields, so that it is added to the
// JSON encoding of the request, as a way to add arbitrary extensions to
// JSON RPC 2.0. If JSON marshaling fails, it returns an error.
func (r *Request) SetExtraField(name string, v interface{}) error {
switch name {
case "id", "jsonrpc", "meta", "method", "params":
return fmt.Errorf("invalid extra field %q", name)
}
r.ExtraFields = append(r.ExtraFields, RequestField{
Name: name,
Value: v,
})
return nil
}
// RequestField is a top-level field that can be added to the JSON-RPC request.
type RequestField struct {
Name string
Value interface{}
}

72
internal/3rdparty/jsonrpc2/response.go vendored Normal file
View File

@ -0,0 +1,72 @@
package jsonrpc2
import (
"encoding/json"
"errors"
)
// Response represents a JSON-RPC response. See
// http://www.jsonrpc.org/specification#response_object.
type Response struct {
ID ID `json:"id"`
Result *json.RawMessage `json:"result,omitempty"`
Error *Error `json:"error,omitempty"`
// Meta optionally provides metadata to include in the response.
//
// NOTE: It is not part of spec. However, it is useful for propagating
// tracing context, etc.
Meta *json.RawMessage `json:"meta,omitempty"`
// SPEC NOTE: The spec says "If there was an error in detecting
// the id in the Request object (e.g. Parse error/Invalid
// Request), it MUST be Null." If we made the ID field nullable,
// then we'd have to make it a pointer type. For simplicity, we're
// ignoring the case where there was an error in detecting the ID
// in the Request object.
}
// MarshalJSON implements json.Marshaler and adds the "jsonrpc":"2.0"
// property.
func (r Response) MarshalJSON() ([]byte, error) {
if (r.Result == nil || len(*r.Result) == 0) && r.Error == nil {
return nil, errors.New("can't marshal *jsonrpc2.Response (must have result or error)")
}
type tmpType Response // avoid infinite MarshalJSON recursion
b, err := json.Marshal(tmpType(r))
if err != nil {
return nil, err
}
b = append(b[:len(b)-1], []byte(`,"jsonrpc":"2.0"}`)...)
return b, nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (r *Response) UnmarshalJSON(data []byte) error {
type tmpType Response
// Detect if the "result" field is JSON "null" or just not present
// by seeing if the field gets overwritten to nil.
*r = Response{Result: &json.RawMessage{}}
if err := json.Unmarshal(data, (*tmpType)(r)); err != nil {
return err
}
if r.Result == nil { // JSON "null"
r.Result = &jsonNull
} else if len(*r.Result) == 0 {
r.Result = nil
}
return nil
}
// SetResult sets r.Result to the JSON representation of v. If JSON
// marshaling fails, it returns an error.
func (r *Response) SetResult(v interface{}) error {
b, err := json.Marshal(v)
if err != nil {
return err
}
r.Result = (*json.RawMessage)(&b)
return nil
}

226
internal/3rdparty/jsonrpc2/stream.go vendored Normal file
View File

@ -0,0 +1,226 @@
package jsonrpc2
import (
"bufio"
"encoding/binary"
"encoding/json"
"fmt"
"io"
"strconv"
"strings"
"sync"
)
// An ObjectStream is a bidirectional stream of JSON-RPC 2.0 objects.
type ObjectStream interface {
// WriteObject writes a JSON-RPC 2.0 object to the stream.
WriteObject(obj interface{}) error
// ReadObject reads the next JSON-RPC 2.0 object from the stream
// and stores it in the value pointed to by v.
ReadObject(v interface{}) error
io.Closer
}
// A bufferedObjectStream is an ObjectStream that uses a buffered
// io.ReadWriteCloser to send and receive objects.
type bufferedObjectStream struct {
conn io.Closer // all writes should go through w, all reads through r
w *bufio.Writer
r *bufio.Reader
codec ObjectCodec
mu sync.Mutex
}
// NewBufferedStream creates a buffered stream from a network
// connection (or other similar interface). The underlying
// objectStream is used to produce the bytes to write to the stream
// for the JSON-RPC 2.0 objects.
func NewBufferedStream(conn io.ReadWriteCloser, codec ObjectCodec) ObjectStream {
switch v := codec.(type) {
case PlainObjectCodec:
v.decoder = json.NewDecoder(conn)
v.encoder = json.NewEncoder(conn)
codec = v
}
return &bufferedObjectStream{
conn: conn,
w: bufio.NewWriter(conn),
r: bufio.NewReader(conn),
codec: codec,
}
}
// WriteObject implements ObjectStream.
func (t *bufferedObjectStream) WriteObject(obj interface{}) error {
t.mu.Lock()
defer t.mu.Unlock()
if err := t.codec.WriteObject(t.w, obj); err != nil {
return err
}
return t.w.Flush()
}
// ReadObject implements ObjectStream.
func (t *bufferedObjectStream) ReadObject(v interface{}) error {
return t.codec.ReadObject(t.r, v)
}
// Close implements ObjectStream.
func (t *bufferedObjectStream) Close() error {
return t.conn.Close()
}
// An ObjectCodec specifies how to encode and decode a JSON-RPC 2.0
// object in a stream.
type ObjectCodec interface {
// WriteObject writes a JSON-RPC 2.0 object to the stream.
WriteObject(stream io.Writer, obj interface{}) error
// ReadObject reads the next JSON-RPC 2.0 object from the stream
// and stores it in the value pointed to by v.
ReadObject(stream *bufio.Reader, v interface{}) error
}
// VarintObjectCodec reads/writes JSON-RPC 2.0 objects with a varint
// header that encodes the byte length.
type VarintObjectCodec struct{}
// WriteObject implements ObjectCodec.
func (VarintObjectCodec) WriteObject(stream io.Writer, obj interface{}) error {
data, err := json.Marshal(obj)
if err != nil {
return err
}
var buf [binary.MaxVarintLen64]byte
b := binary.PutUvarint(buf[:], uint64(len(data)))
if _, err := stream.Write(buf[:b]); err != nil {
return err
}
if _, err := stream.Write(data); err != nil {
return err
}
return nil
}
// ReadObject implements ObjectCodec.
func (VarintObjectCodec) ReadObject(stream *bufio.Reader, v interface{}) error {
b, err := binary.ReadUvarint(stream)
if err != nil {
return err
}
return json.NewDecoder(io.LimitReader(stream, int64(b))).Decode(v)
}
// VSCodeObjectCodec reads/writes JSON-RPC 2.0 objects with
// Content-Length and Content-Type headers, as specified by
// https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#base-protocol.
type VSCodeObjectCodec struct{}
// WriteObject implements ObjectCodec.
func (VSCodeObjectCodec) WriteObject(stream io.Writer, obj interface{}) error {
data, err := json.Marshal(obj)
if err != nil {
return err
}
if _, err := fmt.Fprintf(stream, "Content-Length: %d\r\n\r\n", len(data)); err != nil {
return err
}
if _, err := stream.Write(data); err != nil {
return err
}
return nil
}
// ReadObject implements ObjectCodec.
func (VSCodeObjectCodec) ReadObject(stream *bufio.Reader, v interface{}) error {
var contentLength uint64
for {
line, err := stream.ReadString('\r')
if err != nil {
return err
}
b, err := stream.ReadByte()
if err != nil {
return err
}
if b != '\n' {
return fmt.Errorf(`jsonrpc2: line endings must be \r\n`)
}
if line == "\r" {
break
}
if strings.HasPrefix(line, "Content-Length: ") {
line = strings.TrimPrefix(line, "Content-Length: ")
line = strings.TrimSpace(line)
var err error
contentLength, err = strconv.ParseUint(line, 10, 32)
if err != nil {
return err
}
}
}
if contentLength == 0 {
return fmt.Errorf("jsonrpc2: no Content-Length header found")
}
return json.NewDecoder(io.LimitReader(stream, int64(contentLength))).Decode(v)
}
// PlainObjectCodec reads/writes plain JSON-RPC 2.0 objects without a header.
//
// Deprecated: use NewPlainObjectStream
type PlainObjectCodec struct {
decoder *json.Decoder
encoder *json.Encoder
}
// WriteObject implements ObjectCodec.
func (c PlainObjectCodec) WriteObject(stream io.Writer, v interface{}) error {
if c.encoder != nil {
return c.encoder.Encode(v)
}
return json.NewEncoder(stream).Encode(v)
}
// ReadObject implements ObjectCodec.
func (c PlainObjectCodec) ReadObject(stream *bufio.Reader, v interface{}) error {
if c.decoder != nil {
return c.decoder.Decode(v)
}
return json.NewDecoder(stream).Decode(v)
}
// plainObjectStream reads/writes plain JSON-RPC 2.0 objects without a header.
type plainObjectStream struct {
conn io.Closer
decoder *json.Decoder
encoder *json.Encoder
}
// NewPlainObjectStream creates a buffered stream from a network
// connection (or other similar interface). The underlying
// objectStream produces plain JSON-RPC 2.0 objects without a header.
func NewPlainObjectStream(conn io.ReadWriteCloser) ObjectStream {
return &plainObjectStream{
conn: conn,
encoder: json.NewEncoder(conn),
decoder: json.NewDecoder(conn),
}
}
func (os *plainObjectStream) ReadObject(v interface{}) error {
return os.decoder.Decode(v)
}
// WriteObject serializes a value to JSON and writes it to a stream.
// Not thread-safe, a user must synchronize writes in a multithreaded environment.
func (os *plainObjectStream) WriteObject(v interface{}) error {
return os.encoder.Encode(v)
}
func (os *plainObjectStream) Close() error {
return os.conn.Close()
}

View File

@ -1,412 +0,0 @@
// 版权 @2019 凹语言 作者。保留所有权利。
package app
import (
"bytes"
"errors"
"fmt"
"io"
"io/fs"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"sort"
"strings"
"text/template"
"time"
"github.com/wa-lang/wa/internal/ast"
"github.com/wa-lang/wa/internal/backends/compiler_c"
"github.com/wa-lang/wa/internal/backends/compiler_llvm"
"github.com/wa-lang/wa/internal/backends/compiler_wat"
"github.com/wa-lang/wa/internal/backends/target_spec"
"github.com/wa-lang/wa/internal/config"
"github.com/wa-lang/wa/internal/format"
"github.com/wa-lang/wa/internal/loader"
"github.com/wa-lang/wa/internal/logger"
"github.com/wa-lang/wa/internal/parser"
"github.com/wa-lang/wa/internal/scanner"
"github.com/wa-lang/wa/internal/ssa"
"github.com/wa-lang/wa/internal/token"
"github.com/wa-lang/wa/internal/waroot"
)
// 命令行选项
type Option struct {
Debug bool
TargetArch string
TargetOS string
Clang string
Llc string
}
// 命令行程序对象
type App struct {
opt Option
path string
src string
}
// 构建命令行程序对象
func NewApp(opt *Option) *App {
logger.Tracef(&config.EnableTrace_app, "opt: %+v", opt)
p := &App{}
if opt != nil {
p.opt = *opt
}
if p.opt.Clang == "" {
if runtime.GOOS == "windows" {
p.opt.Clang, _ = exec.LookPath("clang.exe")
} else {
p.opt.Clang, _ = exec.LookPath("clang")
}
if p.opt.Clang == "" {
p.opt.Clang = "clang"
}
}
if p.opt.Llc == "" {
if runtime.GOOS == "windows" {
p.opt.Llc, _ = exec.LookPath("llc.exe")
} else {
p.opt.Llc, _ = exec.LookPath("llc")
}
if p.opt.Llc == "" {
p.opt.Llc = "llc"
}
}
if p.opt.TargetOS == "" {
p.opt.TargetOS = runtime.GOOS
}
if p.opt.TargetArch == "" {
p.opt.TargetArch = runtime.GOARCH
}
return p
}
func (p *App) InitApp(name, pkgpath string, update bool) error {
if name == "" {
return fmt.Errorf("init failed: <%s> is empty", name)
}
if !update {
if _, err := os.Lstat(name); err == nil {
return fmt.Errorf("init failed: <%s> exists", name)
}
}
var info = struct {
Name string
Pkgpath string
Year int
}{
Name: name,
Pkgpath: pkgpath,
Year: time.Now().Year(),
}
appFS := waroot.GetExampleAppFS()
err := fs.WalkDir(appFS, ".", func(path string, d fs.DirEntry, err error) error {
if d == nil || d.IsDir() {
return nil
}
if err != nil {
return err
}
data, err := fs.ReadFile(appFS, path)
if err != nil {
return err
}
tmpl, err := template.New(path).Parse(string(data))
if err != nil {
return err
}
dstpath := filepath.Join(name, path)
os.MkdirAll(filepath.Dir(dstpath), 0777)
f, err := os.Create(dstpath)
if err != nil {
return err
}
defer f.Close()
err = tmpl.Execute(f, &info)
if err != nil {
return err
}
return nil
})
if err != nil {
return err
}
vendorFS := waroot.GetExampleVendorFS()
err = fs.WalkDir(vendorFS, ".", func(path string, d fs.DirEntry, err error) error {
if d == nil || d.IsDir() {
return nil
}
if err != nil {
return err
}
data, err := fs.ReadFile(vendorFS, path)
if err != nil {
return err
}
tmpl, err := template.New(path).Parse(string(data))
if err != nil {
return err
}
dstpath := filepath.Join(name, "vendor", path)
os.MkdirAll(filepath.Dir(dstpath), 0777)
f, err := os.Create(dstpath)
if err != nil {
return err
}
defer f.Close()
err = tmpl.Execute(f, &info)
if err != nil {
return err
}
return nil
})
if err != nil {
return err
}
return nil
}
func (p *App) Fmt(path string) error {
if path == "" {
path, _ = os.Getwd()
}
if strings.HasSuffix(path, "...") {
panic("TODO: fmt dir/...")
}
fi, err := os.Lstat(path)
if err != nil {
return err
}
if fi.IsDir() {
panic("TODO: fmt dir")
}
code, err := format.File(nil, path, nil)
if err != nil {
return err
}
return os.WriteFile(path, code, 0666)
}
func (p *App) Lex(filename string) error {
src, err := p.readSource(filename, nil)
if err != nil {
return err
}
var s scanner.Scanner
fset := token.NewFileSet()
file := fset.AddFile(filename, fset.Base(), len(src))
s.Init(file, src, nil, scanner.ScanComments)
for {
pos, tok, lit := s.Scan()
if tok == token.EOF {
break
}
fmt.Printf("%s\t%s\t%q\n", fset.Position(pos), tok, lit)
}
return nil
}
func (p *App) AST(filename string) error {
fset := token.NewFileSet() // positions are relative to fset
f, err := parser.ParseFile(nil, fset, filename, nil, 0)
if err != nil {
return err
}
return ast.Print(fset, f)
}
func (p *App) SSA(filename string) error {
cfg := config.DefaultConfig()
prog, err := loader.LoadProgram(cfg, filename)
if err != nil {
return err
}
prog.SSAMainPkg.WriteTo(os.Stdout)
var funcNames []string
for name, x := range prog.SSAMainPkg.Members {
if _, ok := x.(*ssa.Function); ok {
funcNames = append(funcNames, name)
}
}
sort.Strings(funcNames)
for _, s := range funcNames {
prog.SSAMainPkg.Func(s).WriteTo(os.Stdout)
}
return nil
}
func (p *App) CIR(filename string) error {
cfg := config.DefaultConfig()
prog, err := loader.LoadProgram(cfg, filename)
if err != nil {
return err
}
var c compiler_c.CompilerC
c.CompilePackage(prog.SSAMainPkg)
print("\n\n")
print(c.String())
return nil
}
func (p *App) LLVM(infile string, outfile string, target string, debug bool) error {
cfg := config.DefaultConfig()
instat, err := os.Stat(infile)
if err != nil {
return err
}
// Calculate the outfile path if not given.
if len(outfile) == 0 {
if instat.IsDir() {
dir := path.Base(infile)
outfile = infile + dir + ".exe"
} else {
ext := path.Ext(infile)
if len(ext) == 0 {
outfile = infile + ".exe"
} else {
pos := strings.Index(infile, ext)
outfile = infile[0:pos] + ".exe"
}
}
}
// Calculate the outfile LLVM-IR file path and the output assembly file path.
llfile, asmfile := "", ""
ext := path.Ext(outfile)
if len(ext) == 0 {
llfile = outfile + ".ll"
asmfile = outfile + ".s"
} else {
pos := strings.Index(outfile, ext)
llfile = outfile[0:pos] + ".ll"
asmfile = outfile[0:pos] + ".s"
}
// Do the real compile work.
prog, err := loader.LoadProgram(cfg, infile)
if err != nil {
return err
}
output, err := compiler_llvm.New(target, debug).Compile(prog)
if err != nil {
return err
}
// Write the outfile LLVM-IR to an intermediate .ll file.
if err := os.WriteFile(llfile, []byte(output), 0644); err != nil {
return err
}
// Invoke command `llc xxx.ll -mtriple=xxx`.
llc := []string{llfile}
if target != "" {
llc = append(llc, "-mtriple", target)
}
cmd0 := exec.Command(p.opt.Llc, llc...)
cmd0.Stderr = os.Stderr
if err := cmd0.Run(); err != nil {
fmt.Fprintf(os.Stderr, "**** failed to invoke LLVM ****\n")
return err
}
// Invoke command `clang xxx.s -o outfile --target=xxx`.
clangArgs := []string{asmfile, "-static", "-o", outfile}
if target != "" {
clangArgs = append(clangArgs, "-target", target)
}
if p.opt.Debug {
clangArgs = append(clangArgs, "-v")
}
cmd1 := exec.Command(p.opt.Clang, clangArgs...)
cmd1.Stderr = os.Stderr
cmd1.Stdout = os.Stdout
if err := cmd1.Run(); err != nil {
fmt.Fprintf(os.Stderr, "**** failed to invoke CLANG ****\n")
return err
}
return nil
}
func (p *App) WASM(filename string, target target_spec.Machine) ([]byte, error) {
cfg := config.DefaultConfig()
prog, err := loader.LoadProgram(cfg, filename)
if err != nil {
return nil, err
}
output, err := compiler_wat.New().Compile(prog, target)
if err != nil {
return nil, err
}
return []byte(output), nil
}
func (p *App) readSource(filename string, src interface{}) ([]byte, error) {
if src != nil {
switch s := src.(type) {
case string:
return []byte(s), nil
case []byte:
return s, nil
case *bytes.Buffer:
if s != nil {
return s.Bytes(), nil
}
case io.Reader:
d, err := io.ReadAll(s)
return d, err
}
return nil, errors.New("invalid source")
}
d, err := os.ReadFile(filename)
return d, err
}
func (p *App) isWaFile(path string) bool {
if fi, err := os.Lstat(path); err == nil && fi.Mode().IsRegular() {
return strings.HasSuffix(strings.ToLower(path), ".wa")
}
return false
}

View File

@ -0,0 +1,56 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appast
import (
"fmt"
"os"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app/appbase"
"wa-lang.org/wa/internal/ast"
"wa-lang.org/wa/internal/parser"
"wa-lang.org/wa/internal/token"
)
var CmdAst = &cli.Command{
Hidden: true,
Name: "ast",
Usage: "parse Wa source code and print ast",
Action: CmdAstAction,
}
func CmdAstAction(c *cli.Context) error {
if c.NArg() == 0 {
fmt.Fprintf(os.Stderr, "no input file")
os.Exit(1)
}
err := PrintAST(c.Args().First())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
}
func PrintAST(filename string) error {
if !appbase.HasExt(filename, ".wa", ".wz") {
return fmt.Errorf("%q is not Wa file", filename)
}
if !appbase.PathExists(filename) {
return fmt.Errorf("%q not found", filename)
}
if !appbase.IsNativeFile(filename) {
return fmt.Errorf("%q must be file", filename)
}
fset := token.NewFileSet()
f, err := parser.ParseFile(nil, fset, filename, nil, 0)
if err != nil {
return err
}
return ast.Print(fset, f)
}

View File

@ -0,0 +1,50 @@
package appbase
import (
"fmt"
"strings"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/config"
)
// 输出路径
func MakeFlag_output() *cli.StringFlag {
return &cli.StringFlag{
Name: "output",
Aliases: []string{"o"},
Usage: "set output file",
Value: "",
}
}
// 构建的目标
func MakeFlag_target() *cli.StringFlag {
return &cli.StringFlag{
Name: "target",
Usage: fmt.Sprintf("set target os (%s)", strings.Join(config.WaOS_List, "|")),
Value: config.WaOS_Default,
}
}
// 构建的 Tags
func MakeFlag_tags() *cli.StringFlag {
return &cli.StringFlag{
Name: "tags",
Usage: "set build tags",
}
}
func MakeFlag_ld_stack_size() *cli.IntFlag {
return &cli.IntFlag{
Name: "ld-stack-size",
Usage: "set stack size",
}
}
func MakeFlag_ld_max_memory() *cli.IntFlag {
return &cli.IntFlag{
Name: "ld-max-memory",
Usage: "set max memory size",
}
}

146
internal/app/appbase/opt.go Normal file
View File

@ -0,0 +1,146 @@
// 版权 @2019 凹语言 作者。保留所有权利。
package appbase
import (
"fmt"
"os"
"os/exec"
"runtime"
"strings"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/config"
)
// 命令行选项
type Option struct {
Debug bool
WaBackend string
BuilgTags []string
TargetArch string
TargetOS string
Clang string
Llc string
LD_StackSize int
LD_MaxMemory int
}
func (opt *Option) Config() *config.Config {
cfg := config.DefaultConfig()
if opt.Debug {
cfg.Debug = true
}
if opt.WaBackend != "" {
cfg.WaBackend = opt.WaBackend
}
if len(opt.BuilgTags) > 0 {
cfg.BuilgTags = append(cfg.BuilgTags, opt.BuilgTags...)
}
if opt.TargetArch != "" {
cfg.WaArch = opt.TargetArch
}
if opt.TargetOS != "" {
cfg.WaOS = opt.TargetOS
}
if opt.LD_StackSize != 0 {
cfg.LDFlags.StackSize = opt.LD_StackSize
}
if opt.LD_MaxMemory != 0 {
cfg.LDFlags.MaxMemory = opt.LD_MaxMemory
}
switch cfg.WaArch {
case "wasm":
cfg.WaSizes.MaxAlign = 8
cfg.WaSizes.WordSize = 4
case "wasm64":
cfg.WaSizes.MaxAlign = 8
cfg.WaSizes.WordSize = 8
case "amd64":
cfg.WaSizes.MaxAlign = 8
cfg.WaSizes.WordSize = 8
case "arm64":
cfg.WaSizes.MaxAlign = 8
cfg.WaSizes.WordSize = 8
case "native":
cfg.WaSizes.MaxAlign = 8
cfg.WaSizes.WordSize = 8
default:
panic("todo")
}
return cfg
}
// 构建命令行程序对象
func (opt *Option) Adjust() {
if opt.Clang == "" {
if runtime.GOOS == "windows" {
opt.Clang, _ = exec.LookPath("clang.exe")
} else {
opt.Clang, _ = exec.LookPath("clang")
}
if opt.Clang == "" {
opt.Clang = "clang"
}
}
if opt.Llc == "" {
if runtime.GOOS == "windows" {
opt.Llc, _ = exec.LookPath("llc.exe")
} else {
opt.Llc, _ = exec.LookPath("llc")
}
if opt.Llc == "" {
opt.Llc = "llc"
}
}
if opt.TargetOS == "" {
opt.TargetOS = config.WaOS_Default
}
if opt.TargetArch == "" {
opt.TargetArch = config.WaArch_Default
}
}
func BuildOptions(c *cli.Context, waBackend ...string) *Option {
opt := &Option{
Debug: c.Bool("debug"),
WaBackend: config.WaBackend_Default,
BuilgTags: strings.Fields(c.String("tags")),
Clang: c.String("clang"),
Llc: c.String("llc"),
LD_StackSize: c.Int("ld-stack-size"),
LD_MaxMemory: c.Int("ld-max-memory"),
}
opt.TargetArch = "wasm"
if len(waBackend) > 0 {
opt.WaBackend = waBackend[0]
}
if target := c.String("target"); !config.CheckWaOS(target) {
fmt.Printf("unknown target: %s\n", c.String("target"))
os.Exit(1)
}
switch c.String("target") {
case "", "wa", "walang":
opt.TargetOS = config.WaOS_Default
case config.WaOS_wasi:
opt.TargetOS = config.WaOS_wasi
case config.WaOS_arduino:
opt.TargetOS = config.WaOS_arduino
case config.WaOS_chrome:
opt.TargetOS = config.WaOS_chrome
case config.WaOS_mvp:
opt.TargetOS = config.WaOS_mvp
default:
fmt.Printf("unreachable: target: %s\n", c.String("target"))
os.Exit(1)
}
opt.Adjust()
return opt
}

View File

@ -0,0 +1,98 @@
// 版权 @2019 凹语言 作者。保留所有权利。
package appbase
import (
"os"
"strings"
"unicode"
)
// 路径名是否包含后缀, 忽略大小写区别
func HasExt(path string, exts ...string) bool {
if path == "" {
return false
}
if len(exts) == 0 {
return true
}
for _, ext := range exts {
if len(path) <= len(ext) {
continue
}
if strings.EqualFold(ext, path[len(path)-len(ext):]) {
return true
}
}
return false
}
// 本地路径存在
func PathExists(path string) bool {
_, err := os.Lstat(path)
return err == nil
}
// 是否为本地存在的文件, 并满足后缀名
func IsNativeFile(path string, exts ...string) bool {
if !HasExt(path, exts...) {
return false
}
fi, err := os.Lstat(path)
if err != nil {
return false
}
return !fi.IsDir()
}
// 是否为本地存在的目录
func IsNativeDir(path string) bool {
fi, err := os.Lstat(path)
if err != nil {
return false
}
return fi.IsDir()
}
// 替换后缀名
func ReplaceExt(path string, extOld, extNew string) string {
return path[:len(path)-len(extOld)] + extNew
}
// 为合法的 app 名字
func IsValidAppName(s string) bool {
if s == "" || s[0] == '_' || (s[0] >= '0' && s[0] <= '9') {
return false
}
for _, c := range []rune(s) {
if c == '_' || (c >= '0' && c <= '9') || unicode.IsLetter(c) {
continue
}
return false
}
return true
}
// 为合法的包路径
func IsValidPkgpath(s string) bool {
if s == "" || s[0] == '_' || (s[0] >= '0' && s[0] <= '9') {
return false
}
for _, c := range []rune(s) {
if c == '_' || c == '.' || c == '/' || (c >= '0' && c <= '9') {
continue
}
if unicode.IsLetter(c) {
continue
}
return false
}
var pkgname = s
if i := strings.LastIndex(s, "/"); i >= 0 {
pkgname = s[i+1:]
}
return IsValidAppName(pkgname)
}
// 是标准库路径

View File

@ -0,0 +1,32 @@
// 版权 @2019 凹语言 作者。保留所有权利。
package appbase
import "testing"
func TestHasExt(t *testing.T) {
var tests = []struct {
path string
exts []string
ok bool
}{
{"", nil, false},
{"a", nil, true},
{"a.wa", []string{".wa"}, true},
{"a.wa", []string{".WA"}, true},
{"a.Wa", []string{".wa"}, true},
{"a.wa", []string{".wa", ".wz"}, true},
{".wa", []string{".wa"}, false},
{".wa", []string{}, true},
}
for i, tt := range tests {
expect := tt.ok
got := HasExt(tt.path, tt.exts...)
if expect != got {
t.Fatalf("%d: expect = %v, got = %v; // %v", i, expect, got, tt)
}
}
}

View File

@ -0,0 +1,208 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appbuild
import (
"fmt"
"os"
"path/filepath"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app/appbase"
"wa-lang.org/wa/internal/backends/compiler_wat"
"wa-lang.org/wa/internal/config"
"wa-lang.org/wa/internal/loader"
"wa-lang.org/wa/internal/wabt"
)
var CmdBuild = &cli.Command{
Name: "build",
Usage: "compile Wa source code",
Flags: []cli.Flag{
appbase.MakeFlag_output(),
appbase.MakeFlag_target(),
appbase.MakeFlag_tags(),
appbase.MakeFlag_ld_stack_size(),
appbase.MakeFlag_ld_max_memory(),
},
Action: CmdBuildAction,
}
func CmdBuildAction(c *cli.Context) error {
input := c.Args().First()
outfile := ""
if input == "" {
input, _ = os.Getwd()
}
var opt = appbase.BuildOptions(c)
_, err := BuildApp(opt, input, outfile)
if err != nil {
return err
}
return err
}
func BuildApp(opt *appbase.Option, input, outfile string) (wasmBytes []byte, err error) {
// 路径是否存在
if !appbase.PathExists(input) {
fmt.Printf("%q not found\n", input)
os.Exit(1)
}
// 输出参数是否合法, 必须是 wasm
if outfile != "" && !appbase.HasExt(outfile, ".wasm") {
fmt.Printf("%q is not valid output path\n", outfile)
os.Exit(1)
}
// 已经是 wasm, 直接返回
if appbase.HasExt(input, ".wasm") {
return os.ReadFile(input)
}
// 只编译 wat 文件, 输出路径相同, 后缀名调整
if appbase.HasExt(input, ".wat") {
// 设置默认输出目标
if outfile == "" {
outfile = appbase.ReplaceExt(input, ".wat", ".wasm")
}
watData, err := os.ReadFile(input)
if err != nil {
fmt.Printf("read %s failed: %v\n", input, err)
os.Exit(1)
}
wasmBytes, err := wabt.Wat2Wasm(watData)
if err != nil {
fmt.Printf("wat2wasm %s failed: %v\n", input, err)
os.Exit(1)
}
// 写到文件
err = os.WriteFile(outfile, wasmBytes, 0666)
if err != nil {
fmt.Printf("write %s failed: %v\n", outfile, err)
os.Exit(1)
}
// OK
return wasmBytes, nil
}
// 只编译 wa/wz 文件, 输出路径相同, 后缀名调整
if appbase.HasExt(input, ".wa", ".wz") {
_, watOutput, err := buildWat(opt, input)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// 设置默认输出目标
if outfile == "" {
outfile = appbase.ReplaceExt(input, ".wa", ".wasm")
}
// wat 写到文件
watOutfile := appbase.ReplaceExt(outfile, ".wasm", ".wat")
err = os.WriteFile(watOutfile, watOutput, 0666)
if err != nil {
fmt.Printf("write %s failed: %v\n", outfile, err)
os.Exit(1)
}
// wat 编译为 wasm
wasmBytes, err := wabt.Wat2Wasm(watOutput)
if err != nil {
fmt.Printf("wat2wasm %s failed: %v\n", input, err)
os.Exit(1)
}
// wasm 写到文件
err = os.WriteFile(outfile, wasmBytes, 0666)
if err != nil {
fmt.Printf("write %s failed: %v\n", outfile, err)
os.Exit(1)
}
// OK
return wasmBytes, nil
}
// 构建目录
{
if !appbase.IsNativeDir(input) {
fmt.Printf("%q is not valid output path\n", outfile)
os.Exit(1)
}
// 尝试读取模块信息
manifest, err := config.LoadManifest(nil, input)
if err != nil {
fmt.Printf("%q is invalid wa moudle\n", input)
os.Exit(1)
}
if err := manifest.Valid(); err != nil {
fmt.Printf("%q is invalid wa module; %v\n", input, err)
os.Exit(1)
}
if outfile == "" {
if !manifest.IsStd {
outfile = filepath.Join(manifest.Root, "output", manifest.Pkg.Name) + ".wasm"
os.MkdirAll(filepath.Join(manifest.Root, "output"), 0777)
} else {
outfile = "a.out." + manifest.Pkg.Name + ".wasm"
}
}
// 编译出 wat 文件
_, watOutput, err := buildWat(opt, input)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// wat 写到文件
watOutfile := appbase.ReplaceExt(outfile, ".wasm", ".wat")
err = os.WriteFile(watOutfile, watOutput, 0666)
if err != nil {
fmt.Printf("write %s failed: %v\n", outfile, err)
os.Exit(1)
}
// wat 编译为 wasm
wasmBytes, err := wabt.Wat2Wasm(watOutput)
if err != nil {
fmt.Printf("wat2wasm %s failed: %v\n", input, err)
os.Exit(1)
}
// wasm 写到文件
err = os.WriteFile(outfile, wasmBytes, 0666)
if err != nil {
fmt.Printf("write %s failed: %v\n", outfile, err)
os.Exit(1)
}
// OK
return wasmBytes, nil
}
}
func buildWat(opt *appbase.Option, filename string) (*loader.Program, []byte, error) {
cfg := opt.Config()
prog, err := loader.LoadProgram(cfg, filename)
if err != nil {
return prog, nil, err
}
output, err := compiler_wat.New().Compile(prog, "main")
if err != nil {
return prog, nil, err
}
return prog, []byte(output), nil
}

View File

@ -0,0 +1,52 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appcir
import (
"fmt"
"os"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app/appbase"
"wa-lang.org/wa/internal/backends/compiler_c"
"wa-lang.org/wa/internal/loader"
)
var CmdCir = &cli.Command{
Hidden: true,
Name: "cir",
Usage: "print cir code",
Flags: []cli.Flag{
appbase.MakeFlag_output(),
appbase.MakeFlag_target(),
appbase.MakeFlag_tags(),
},
Action: func(c *cli.Context) error {
if c.NArg() == 0 {
fmt.Fprintf(os.Stderr, "no input file")
os.Exit(1)
}
opt := appbase.BuildOptions(c)
err := PrintCIR(opt, c.Args().First())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}
func PrintCIR(opt *appbase.Option, filename string) error {
cfg := opt.Config()
prog, err := loader.LoadProgram(cfg, filename)
if err != nil {
return err
}
var c compiler_c.CompilerC
c.CompilePackage(prog.SSAMainPkg)
fmt.Println(c.String())
return nil
}

View File

@ -0,0 +1,113 @@
package appdev
import (
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"wa-lang.org/wa/api"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/config"
)
var CmdDev = &cli.Command{
Hidden: true,
Name: "debug",
Usage: "only for dev/debug",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "hello",
},
&cli.BoolFlag{
Name: "count-code-lines",
},
},
Action: func(c *cli.Context) error {
if c.Bool("count-code-lines") {
RunCountCodeLines()
os.Exit(0)
}
if c.Bool("hello") {
wat, err := api.BuildFile(
config.DefaultConfig(),
"hello.wa", "func main() { println(123) }",
)
if err != nil {
if len(wat) != 0 {
fmt.Println(string(wat))
}
fmt.Println(err)
os.Exit(1)
}
fmt.Println(string(wat))
os.Exit(0)
}
fmt.Println("...dev...")
return nil
},
}
func RunCountCodeLines() {
var dir = "."
if len(os.Args) > 1 {
dir = os.Args[1]
}
total := 0
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
log.Fatal("filepath.Walk: ", err)
return err
}
if info.IsDir() {
return nil
}
data, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal("ioutil.ReadFile: ", err)
}
if needSkip(path, data) {
return nil
}
n := countLine(data)
fmt.Println(path, n)
total += n
return nil
})
fmt.Printf("total %d\n", total)
}
func needSkip(path string, data []byte) bool {
if !hasExt(path, ".wa", ".go", ".ws") {
return true
}
if strings.Contains(path, "3rdparty") {
return true
}
if bytes.Contains(data, []byte("The Go Authors")) {
return true
}
return false
}
func countLine(data []byte) int {
return bytes.Count(data, []byte("\n"))
}
func hasExt(name string, extensions ...string) bool {
for _, ext := range extensions {
if strings.HasSuffix(name, ext) {
return true
}
}
return false
}

Some files were not shown because too many files have changed in this diff Show More