Compare commits

...

301 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
555 changed files with 50100 additions and 10785 deletions

View File

@ -23,7 +23,7 @@ jobs:
go-version: 1.17
- run: make -C internal/app/wawasm
- run: make -C _examples/snake publish
- run: make -C waroot/examples/snake publish
- name: Deploy
uses: peaceiris/actions-gh-pages@v3

View File

@ -30,10 +30,9 @@ jobs:
- run: go install
- run: wa -h
- run: wa hello.wa
- run: wa run _examples/prime
- run: wa run hello.wa
- run: wa run -target=chrome 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:
@ -60,10 +59,9 @@ jobs:
- run: go install
- run: wa -h
- run: wa hello.wa
- run: wa run _examples/prime
- run: wa run hello.wa
- run: wa run -target=chrome 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
@ -86,7 +84,6 @@ jobs:
- run: go install
- run: wa -h
- run: wa hello.wa
- run: wa run _examples/prime
- run: wa run hello.wa
- run: wa run -target=chrome 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

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
/.fleet
/.vscode
/_build*
/hello
wa
wa.exe

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

@ -29,9 +29,9 @@ stages:
chmod +X output/wa-lang-linux64/wa
./output/wa-lang-linux64/wa
./output/wa-lang-linux64/wa -h
./output/wa-lang-linux64/wa hello.wa
./output/wa-lang-linux64/wa run _examples/prime
./output/wa-lang-linux64/wa run hello.wa
#./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:

View File

@ -29,9 +29,9 @@ stages:
chmod +X output/wa-lang-linux64/wa
./output/wa-lang-linux64/wa
./output/wa-lang-linux64/wa -h
./output/wa-lang-linux64/wa hello.wa
./output/wa-lang-linux64/wa run _examples/prime
./output/wa-lang-linux64/wa run hello.wa
#./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:

View File

@ -29,9 +29,9 @@ stages:
chmod +X output/wa-lang-linux64/wa
./output/wa-lang-linux64/wa
./output/wa-lang-linux64/wa -h
./output/wa-lang-linux64/wa hello.wa
./output/wa-lang-linux64/wa run _examples/prime
./output/wa-lang-linux64/wa run hello.wa
#./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:

View File

@ -1,17 +1,15 @@
# 版权 @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
@ -21,14 +19,17 @@ arduino-build:
xxd -i a.out.wasm > app.wasm.h
ci-test-all:
go install
go test ./...
@echo "== std test begin =="
go run main.go test fmt
go run main.go test std
@echo "== std ok =="
go run main.go hello.wa
go run main.go run ./waroot/hello.wa
cd waroot && go run ../main.go run hello.wa
make -C ./_examples ci-test-all
make -C ./waroot/examples ci-test-all
clean:
-rm a.out*

View File

@ -10,6 +10,7 @@
![](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)
@ -36,14 +37,6 @@
![](https://wa-lang.org/st0018-03.jpg)
## 本地安装和测试:
Go >= 1.17
1. `go install wa-lang.org/wa@latest`
2. `wa init -name=_examples/hi`
3. `wa run _examples/hi`
## 例子: 凹语言
打印字符和调用函数:
@ -51,9 +44,11 @@ Go >= 1.17
```wa
import "fmt"
global year: i32 = 2023
func main {
println("你好,凹语言!")
println(add(40, 2))
println("hello, Wa!")
println(add(40, 2), year)
fmt.Println(1+1)
}
@ -66,9 +61,9 @@ func add(a: i32, b: i32) => i32 {
运行并输出结果:
```
$ go run main.go hello.wa
$ wa run hello.wa
你好,凹语言!
42
42 2023
2
```
@ -81,7 +76,7 @@ $ go run main.go hello.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
@ -97,7 +92,7 @@ func main {
运行并输出结果:
```
$ go run main.go run _examples/prime
$ cd waroot && wa run examples/prime
2
3
5
@ -134,5 +129,23 @@ $ go run main.go run _examples/prime
运行的结果和英文语法的示例相同。
更多例子 [_examples](_examples)
更多例子 [waroot/examples](waroot/examples)
## 贡献者名单
|贡献者|贡献点|
| --- | --- |
|柴树杉| 35000|
|丁尔男| 42500|
|史斌 | 29000|
|扈梦明| 14000|
|赵普明| 17000|
|宋汝阳| 2000|
|刘云峰| 1000|
|王湘南| 1000|
|王泽龙| 1000|
|吴烜 | 3000|
|刘斌 | 2500|
|尹贻浩| 2000|
贡献点变更记录见 [waroot/cplog](waroot/cplog) 目录。

View File

@ -8,10 +8,8 @@
<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/wa-lang.org/wa.svg)](https://pkg.go.dev/wa-lang.org/wa)
[![license](https://img.shields.io/github/license/wa-lang/wa.svg)](https://github.com/wa-lang/wa/blob/master/LICENSE)
</div>
@ -21,7 +19,8 @@ Instead of requiring complex toolchains to set up, you can simply go install it
![](docs/images/logo/logo-animate1.svg)
- Home: [https://wa-lang.org](https://wa-lang.org)
- 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)
@ -36,32 +35,22 @@ Instead of requiring complex toolchains to set up, you can simply go install it
## Snake Game
- Play: [https://wa-lang.org/wa/snake/](https://wa-lang.org/wa/snake/)
- Code: [_examples/snake/README-en.md](_examples/snake/README-en.md)
- Code: [waroot/examples/snake/README-en.md](waroot/examples/snake/README-en.md)
![](https://wa-lang.org/st0018-03.jpg)
## Install and Run:
Go >= 1.17
1. `go install wa-lang.org/wa@latest`
2. `wa init -name=_examples/hi`
3. `wa run _examples/hi`
> 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). We do not accept PR only about 3rdparty changes.
## Example: Print Wa
Print rune and call function
```wa
// Copyright @2019-2022 The Wa author. All rights reserved.
import "fmt"
global year: i32 = 2023
func main {
println("hello, Wa!")
println(add(40, 2))
println(add(40, 2), year)
fmt.Println(1+1)
}
@ -74,9 +63,9 @@ func add(a: i32, b: i32) => i32 {
Execute the program:
```
$ go run main.go hello.wa
$ wa run hello.wa
hello, Wa!
42
42 2023
2
```
@ -84,10 +73,10 @@ hello, Wa!
Print prime numbers up to 30:
```
```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
@ -103,7 +92,7 @@ func main {
Execute the program:
```
$ go run main.go run _examples/prime
$ cd waroot && wa run examples/prime
2
3
5
@ -142,5 +131,21 @@ Print prime numbers up to 30:
Output is the same as the previous example.
More examples [_examples](_examples)
More examples [waroot/examples](waroot/examples)
## Contributors
|Contributor|Contribution points|
| --- | --- |
|柴树杉| 35000|
|丁尔男| 42500|
|史斌 | 29000|
|扈梦明| 14000|
|赵普明| 17000|
|宋汝阳| 2000|
|刘云峰| 1000|
|王湘南| 1000|
|王泽龙| 1000|
|吴烜 | 3000|
|刘斌 | 2500|
|尹贻浩| 2000|

View File

@ -1,11 +0,0 @@
# 版权 @2023 凹语言 作者。保留所有权利。
dev:
go run . -dbg=a1.out.dbg -wat=a1.out.wat
-rm wa.wasm
GOOS=js GOARCH=wasm go build -o wa.wasm
node run-go-wasm.js wa.wasm -dbg=a2.out.dbg -wat=a2.out.wat
clean:
-rm *.out.* *.wasm

View File

@ -1,81 +0,0 @@
// 版权 @2022 凹语言 作者。保留所有权利。
package main
import (
"wa-lang.org/wa/api"
"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/logger"
)
var waError error
func waGetError() error {
return waError
}
func waGetErrorText() string {
if waError != nil {
return waError.Error()
} else {
return ""
}
}
func waSetError(err error) {
waError = err
}
func waClearError() {
waError = nil
}
func waDebugString(filename, code string) string {
cfg := api.DefaultConfig()
cfg.WaArch = api.WaArch_wasm
cfg.WaOS = api.WaOS_chrome
prog, err := loader.LoadProgramFile(cfg, filename, code)
if err != nil || prog == nil {
return err.Error()
}
return prog.DebugString()
}
func waGenerateWat(filename, code string) string {
cfg := api.DefaultConfig()
cfg.WaArch = api.WaArch_wasm
cfg.WaOS = api.WaOS_chrome
wat, err := waBuildFile(cfg, filename, code)
if err != nil {
if waGetError() == nil {
waSetError(err)
}
return ""
}
return string(wat)
}
func waFormatCode(filename, code string) string {
newCode, err := api.FormatCode(filename, code)
if err != nil {
if waGetError() == nil {
waSetError(err)
}
return code
}
return newCode
}
// 构建 wat 目标
func waBuildFile(cfg *config.Config, filename string, src interface{}) (wat []byte, err error) {
prog, err := loader.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, "main")
return []byte(watOut), err
}

View File

@ -1,56 +0,0 @@
// 版权 @2022 凹语言 作者。保留所有权利。
package main
import (
"flag"
"fmt"
"os"
)
var (
flagDbgOut = flag.String("dbg", "a.out.dbg", "debug output file")
flagWatOut = flag.String("wat", "a.out.wat", "wat output file")
)
func main() {
flag.Parse()
os.Remove(*flagDbgOut)
os.Remove(*flagWatOut)
fmt.Println("=== WARN: only for build wa.wasm === ")
waClearError()
outDbg := waDebugString(waName, waCode)
outWat := waGenerateWat(waName, waCode)
if serr := waGetErrorText(); serr != "" {
fmt.Println("ERR:", serr)
os.Exit(1)
}
os.WriteFile(*flagDbgOut, []byte(outDbg), 0666)
os.WriteFile(*flagWatOut, []byte(outWat), 0666)
fmt.Println("Done")
}
const waName = "hello.wa"
const waCode = `// 版权 @2019 凹语言 作者。保留所有权利。
import "fmt"
import "runtime"
func main {
println("你好,凹语言!", runtime.WAOS)
println(add(40, 2))
fmt.Println(1+1)
}
func add(a: i32, b: i32) => i32 {
return a+b
}
`

View File

@ -1,638 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Go1.17.13
(() => {
// Map multiple JavaScript environments to a single common API,
// preferring web standards over Node.js API.
//
// Environments considered:
// - Browsers
// - Node.js
// - Electron
// - Parcel
// - Webpack
if (typeof global !== "undefined") {
// global already exists
} else if (typeof window !== "undefined") {
window.global = window;
} else if (typeof self !== "undefined") {
self.global = self;
} else {
throw new Error("cannot export Go (neither global, window nor self is defined)");
}
if (!global.require && typeof require !== "undefined") {
global.require = require;
}
if (!global.fs && global.require) {
const fs = require("fs");
if (typeof fs === "object" && fs !== null && Object.keys(fs).length !== 0) {
global.fs = fs;
}
}
const enosys = () => {
const err = new Error("not implemented");
err.code = "ENOSYS";
return err;
};
if (!global.fs) {
let outputBuf = "";
global.fs = {
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
writeSync(fd, buf) {
outputBuf += decoder.decode(buf);
const nl = outputBuf.lastIndexOf("\n");
if (nl != -1) {
console.log(outputBuf.substr(0, nl));
outputBuf = outputBuf.substr(nl + 1);
}
return buf.length;
},
write(fd, buf, offset, length, position, callback) {
if (offset !== 0 || length !== buf.length || position !== null) {
callback(enosys());
return;
}
const n = this.writeSync(fd, buf);
callback(null, n);
},
chmod(path, mode, callback) { callback(enosys()); },
chown(path, uid, gid, callback) { callback(enosys()); },
close(fd, callback) { callback(enosys()); },
fchmod(fd, mode, callback) { callback(enosys()); },
fchown(fd, uid, gid, callback) { callback(enosys()); },
fstat(fd, callback) { callback(enosys()); },
fsync(fd, callback) { callback(null); },
ftruncate(fd, length, callback) { callback(enosys()); },
lchown(path, uid, gid, callback) { callback(enosys()); },
link(path, link, callback) { callback(enosys()); },
lstat(path, callback) { callback(enosys()); },
mkdir(path, perm, callback) { callback(enosys()); },
open(path, flags, mode, callback) { callback(enosys()); },
read(fd, buffer, offset, length, position, callback) { callback(enosys()); },
readdir(path, callback) { callback(enosys()); },
readlink(path, callback) { callback(enosys()); },
rename(from, to, callback) { callback(enosys()); },
rmdir(path, callback) { callback(enosys()); },
stat(path, callback) { callback(enosys()); },
symlink(path, link, callback) { callback(enosys()); },
truncate(path, length, callback) { callback(enosys()); },
unlink(path, callback) { callback(enosys()); },
utimes(path, atime, mtime, callback) { callback(enosys()); },
};
}
if (!global.process) {
global.process = {
getuid() { return -1; },
getgid() { return -1; },
geteuid() { return -1; },
getegid() { return -1; },
getgroups() { throw enosys(); },
pid: -1,
ppid: -1,
umask() { throw enosys(); },
cwd() { throw enosys(); },
chdir() { throw enosys(); },
}
}
if (!global.crypto && global.require) {
const nodeCrypto = require("crypto");
global.crypto = {
getRandomValues(b) {
nodeCrypto.randomFillSync(b);
},
};
}
if (!global.crypto) {
throw new Error("global.crypto is not available, polyfill required (getRandomValues only)");
}
if (!global.performance) {
global.performance = {
now() {
const [sec, nsec] = process.hrtime();
return sec * 1000 + nsec / 1000000;
},
};
}
if (!global.TextEncoder && global.require) {
global.TextEncoder = require("util").TextEncoder;
}
if (!global.TextEncoder) {
throw new Error("global.TextEncoder is not available, polyfill required");
}
if (!global.TextDecoder && global.require) {
global.TextDecoder = require("util").TextDecoder;
}
if (!global.TextDecoder) {
throw new Error("global.TextDecoder is not available, polyfill required");
}
// End of polyfills for common API.
const encoder = new TextEncoder("utf-8");
const decoder = new TextDecoder("utf-8");
global.Go = class {
constructor() {
this.argv = ["js"];
this.env = {};
this.exit = (code) => {
if (code !== 0) {
console.warn("exit code:", code);
}
};
this._exitPromise = new Promise((resolve) => {
this._resolveExitPromise = resolve;
});
this._pendingEvent = null;
this._scheduledTimeouts = new Map();
this._nextCallbackTimeoutID = 1;
const setInt64 = (addr, v) => {
this.mem.setUint32(addr + 0, v, true);
this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
}
const getInt64 = (addr) => {
const low = this.mem.getUint32(addr + 0, true);
const high = this.mem.getInt32(addr + 4, true);
return low + high * 4294967296;
}
const loadValue = (addr) => {
const f = this.mem.getFloat64(addr, true);
if (f === 0) {
return undefined;
}
if (!isNaN(f)) {
return f;
}
const id = this.mem.getUint32(addr, true);
return this._values[id];
}
const storeValue = (addr, v) => {
const nanHead = 0x7FF80000;
if (typeof v === "number" && v !== 0) {
if (isNaN(v)) {
this.mem.setUint32(addr + 4, nanHead, true);
this.mem.setUint32(addr, 0, true);
return;
}
this.mem.setFloat64(addr, v, true);
return;
}
if (v === undefined) {
this.mem.setFloat64(addr, 0, true);
return;
}
let id = this._ids.get(v);
if (id === undefined) {
id = this._idPool.pop();
if (id === undefined) {
id = this._values.length;
}
this._values[id] = v;
this._goRefCounts[id] = 0;
this._ids.set(v, id);
}
this._goRefCounts[id]++;
let typeFlag = 0;
switch (typeof v) {
case "object":
if (v !== null) {
typeFlag = 1;
}
break;
case "string":
typeFlag = 2;
break;
case "symbol":
typeFlag = 3;
break;
case "function":
typeFlag = 4;
break;
}
this.mem.setUint32(addr + 4, nanHead | typeFlag, true);
this.mem.setUint32(addr, id, true);
}
const loadSlice = (addr) => {
const array = getInt64(addr + 0);
const len = getInt64(addr + 8);
return new Uint8Array(this._inst.exports.mem.buffer, array, len);
}
const loadSliceOfValues = (addr) => {
const array = getInt64(addr + 0);
const len = getInt64(addr + 8);
const a = new Array(len);
for (let i = 0; i < len; i++) {
a[i] = loadValue(array + i * 8);
}
return a;
}
const loadString = (addr) => {
const saddr = getInt64(addr + 0);
const len = getInt64(addr + 8);
return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
}
const timeOrigin = Date.now() - performance.now();
this.importObject = {
go: {
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
// This changes the SP, thus we have to update the SP used by the imported function.
// func wasmExit(code int32)
"runtime.wasmExit": (sp) => {
sp >>>= 0;
const code = this.mem.getInt32(sp + 8, true);
this.exited = true;
delete this._inst;
delete this._values;
delete this._goRefCounts;
delete this._ids;
delete this._idPool;
this.exit(code);
},
// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
"runtime.wasmWrite": (sp) => {
sp >>>= 0;
const fd = getInt64(sp + 8);
const p = getInt64(sp + 16);
const n = this.mem.getInt32(sp + 24, true);
fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n));
},
// func resetMemoryDataView()
"runtime.resetMemoryDataView": (sp) => {
sp >>>= 0;
this.mem = new DataView(this._inst.exports.mem.buffer);
},
// func nanotime1() int64
"runtime.nanotime1": (sp) => {
sp >>>= 0;
setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
},
// func walltime() (sec int64, nsec int32)
"runtime.walltime": (sp) => {
sp >>>= 0;
const msec = (new Date).getTime();
setInt64(sp + 8, msec / 1000);
this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
},
// func scheduleTimeoutEvent(delay int64) int32
"runtime.scheduleTimeoutEvent": (sp) => {
sp >>>= 0;
const id = this._nextCallbackTimeoutID;
this._nextCallbackTimeoutID++;
this._scheduledTimeouts.set(id, setTimeout(
() => {
this._resume();
while (this._scheduledTimeouts.has(id)) {
// for some reason Go failed to register the timeout event, log and try again
// (temporary workaround for https://github.com/golang/go/issues/28975)
console.warn("scheduleTimeoutEvent: missed timeout event");
this._resume();
}
},
getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
));
this.mem.setInt32(sp + 16, id, true);
},
// func clearTimeoutEvent(id int32)
"runtime.clearTimeoutEvent": (sp) => {
sp >>>= 0;
const id = this.mem.getInt32(sp + 8, true);
clearTimeout(this._scheduledTimeouts.get(id));
this._scheduledTimeouts.delete(id);
},
// func getRandomData(r []byte)
"runtime.getRandomData": (sp) => {
sp >>>= 0;
crypto.getRandomValues(loadSlice(sp + 8));
},
// func finalizeRef(v ref)
"syscall/js.finalizeRef": (sp) => {
sp >>>= 0;
const id = this.mem.getUint32(sp + 8, true);
this._goRefCounts[id]--;
if (this._goRefCounts[id] === 0) {
const v = this._values[id];
this._values[id] = null;
this._ids.delete(v);
this._idPool.push(id);
}
},
// func stringVal(value string) ref
"syscall/js.stringVal": (sp) => {
sp >>>= 0;
storeValue(sp + 24, loadString(sp + 8));
},
// func valueGet(v ref, p string) ref
"syscall/js.valueGet": (sp) => {
sp >>>= 0;
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 32, result);
},
// func valueSet(v ref, p string, x ref)
"syscall/js.valueSet": (sp) => {
sp >>>= 0;
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
},
// func valueDelete(v ref, p string)
"syscall/js.valueDelete": (sp) => {
sp >>>= 0;
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
},
// func valueIndex(v ref, i int) ref
"syscall/js.valueIndex": (sp) => {
sp >>>= 0;
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
},
// valueSetIndex(v ref, i int, x ref)
"syscall/js.valueSetIndex": (sp) => {
sp >>>= 0;
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
},
// func valueCall(v ref, m string, args []ref) (ref, bool)
"syscall/js.valueCall": (sp) => {
sp >>>= 0;
try {
const v = loadValue(sp + 8);
const m = Reflect.get(v, loadString(sp + 16));
const args = loadSliceOfValues(sp + 32);
const result = Reflect.apply(m, v, args);
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 56, result);
this.mem.setUint8(sp + 64, 1);
} catch (err) {
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 56, err);
this.mem.setUint8(sp + 64, 0);
}
},
// func valueInvoke(v ref, args []ref) (ref, bool)
"syscall/js.valueInvoke": (sp) => {
sp >>>= 0;
try {
const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16);
const result = Reflect.apply(v, undefined, args);
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 40, result);
this.mem.setUint8(sp + 48, 1);
} catch (err) {
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 40, err);
this.mem.setUint8(sp + 48, 0);
}
},
// func valueNew(v ref, args []ref) (ref, bool)
"syscall/js.valueNew": (sp) => {
sp >>>= 0;
try {
const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16);
const result = Reflect.construct(v, args);
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 40, result);
this.mem.setUint8(sp + 48, 1);
} catch (err) {
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 40, err);
this.mem.setUint8(sp + 48, 0);
}
},
// func valueLength(v ref) int
"syscall/js.valueLength": (sp) => {
sp >>>= 0;
setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
},
// valuePrepareString(v ref) (ref, int)
"syscall/js.valuePrepareString": (sp) => {
sp >>>= 0;
const str = encoder.encode(String(loadValue(sp + 8)));
storeValue(sp + 16, str);
setInt64(sp + 24, str.length);
},
// valueLoadString(v ref, b []byte)
"syscall/js.valueLoadString": (sp) => {
sp >>>= 0;
const str = loadValue(sp + 8);
loadSlice(sp + 16).set(str);
},
// func valueInstanceOf(v ref, t ref) bool
"syscall/js.valueInstanceOf": (sp) => {
sp >>>= 0;
this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
},
// func copyBytesToGo(dst []byte, src ref) (int, bool)
"syscall/js.copyBytesToGo": (sp) => {
sp >>>= 0;
const dst = loadSlice(sp + 8);
const src = loadValue(sp + 32);
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
this.mem.setUint8(sp + 48, 0);
return;
}
const toCopy = src.subarray(0, dst.length);
dst.set(toCopy);
setInt64(sp + 40, toCopy.length);
this.mem.setUint8(sp + 48, 1);
},
// func copyBytesToJS(dst ref, src []byte) (int, bool)
"syscall/js.copyBytesToJS": (sp) => {
sp >>>= 0;
const dst = loadValue(sp + 8);
const src = loadSlice(sp + 16);
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
this.mem.setUint8(sp + 48, 0);
return;
}
const toCopy = src.subarray(0, dst.length);
dst.set(toCopy);
setInt64(sp + 40, toCopy.length);
this.mem.setUint8(sp + 48, 1);
},
"debug": (value) => {
console.log(value);
},
}
};
}
async run(instance) {
if (!(instance instanceof WebAssembly.Instance)) {
throw new Error("Go.run: WebAssembly.Instance expected");
}
this._inst = instance;
this.mem = new DataView(this._inst.exports.mem.buffer);
this._values = [ // JS values that Go currently has references to, indexed by reference id
NaN,
0,
null,
true,
false,
global,
this,
];
this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
this._ids = new Map([ // mapping from JS values to reference ids
[0, 1],
[null, 2],
[true, 3],
[false, 4],
[global, 5],
[this, 6],
]);
this._idPool = []; // unused ids that have been garbage collected
this.exited = false; // whether the Go program has exited
// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
let offset = 4096;
const strPtr = (str) => {
const ptr = offset;
const bytes = encoder.encode(str + "\0");
new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
offset += bytes.length;
if (offset % 8 !== 0) {
offset += 8 - (offset % 8);
}
return ptr;
};
const argc = this.argv.length;
const argvPtrs = [];
this.argv.forEach((arg) => {
argvPtrs.push(strPtr(arg));
});
argvPtrs.push(0);
const keys = Object.keys(this.env).sort();
keys.forEach((key) => {
argvPtrs.push(strPtr(`${key}=${this.env[key]}`));
});
argvPtrs.push(0);
const argv = offset;
argvPtrs.forEach((ptr) => {
this.mem.setUint32(offset, ptr, true);
this.mem.setUint32(offset + 4, 0, true);
offset += 8;
});
// The linker guarantees global data starts from at least wasmMinDataAddr.
// Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr.
const wasmMinDataAddr = 4096 + 8192;
if (offset >= wasmMinDataAddr) {
throw new Error("total length of command line and environment variables exceeds limit");
}
this._inst.exports.run(argc, argv);
if (this.exited) {
this._resolveExitPromise();
}
await this._exitPromise;
}
_resume() {
if (this.exited) {
throw new Error("Go program has already exited");
}
this._inst.exports.resume();
if (this.exited) {
this._resolveExitPromise();
}
}
_makeFuncWrapper(id) {
const go = this;
return function () {
const event = { id: id, this: this, args: arguments };
go._pendingEvent = event;
go._resume();
return event.result;
};
}
}
if (
typeof module !== "undefined" &&
global.require &&
global.require.main === module &&
global.process &&
global.process.versions &&
!global.process.versions.electron
) {
if (process.argv.length < 3) {
console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
process.exit(1);
}
const go = new Go();
go.argv = process.argv.slice(2);
go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
go.exit = process.exit;
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
process.on("exit", (code) => { // Node.js exits if no event handler is pending
if (code === 0 && !go.exited) {
// deadlock, make Go print error and stack traces
go._pendingEvent = { id: 0 };
go._resume();
}
});
return go.run(result.instance);
}).catch((err) => {
console.error(err);
process.exit(1);
});
}
})();

View File

@ -1,28 +0,0 @@
# 版权 @2023 凹语言 作者。保留所有权利。
default:
ci-test-all:
@echo "== _examples test begin =="
# loop forever
# cd ./arduino && make
# cd ./arduino-wat && make
cd ./brainfuck && make
cd ./expr && make
cd ./hello && make
cd ./pkg && make
cd ./prime && make
cd ./reftoptr && make
# snake
cd ./snake && make publish
go run ../main.go interface_named.wa
go run ../main.go struct.wa
@echo "== _examples ok =="
clean:

View File

@ -1,132 +0,0 @@
unsigned char app_wasm[] = {
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x2a, 0x08, 0x60,
0x01, 0x7f, 0x00, 0x60, 0x02, 0x7f, 0x7f, 0x00, 0x60, 0x00, 0x01, 0x7f,
0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x04, 0x7f, 0x7f, 0x7f, 0x7f, 0x01,
0x7f, 0x60, 0x01, 0x7f, 0x02, 0x7f, 0x7f, 0x60, 0x00, 0x00, 0x60, 0x03,
0x7f, 0x7f, 0x7f, 0x00, 0x02, 0x6f, 0x06, 0x07, 0x61, 0x72, 0x64, 0x75,
0x69, 0x6e, 0x6f, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x00, 0x00, 0x07,
0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x07, 0x70, 0x69, 0x6e, 0x4d,
0x6f, 0x64, 0x65, 0x00, 0x01, 0x07, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e,
0x6f, 0x0c, 0x64, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x57, 0x72, 0x69,
0x74, 0x65, 0x00, 0x01, 0x07, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f,
0x06, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x00, 0x02, 0x07, 0x61, 0x72,
0x64, 0x75, 0x69, 0x6e, 0x6f, 0x09, 0x67, 0x65, 0x74, 0x50, 0x69, 0x6e,
0x4c, 0x45, 0x44, 0x00, 0x02, 0x07, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e,
0x6f, 0x05, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x01, 0x03, 0x13, 0x12,
0x03, 0x00, 0x04, 0x05, 0x03, 0x00, 0x06, 0x06, 0x00, 0x00, 0x01, 0x06,
0x06, 0x06, 0x06, 0x07, 0x07, 0x06, 0x04, 0x04, 0x01, 0x70, 0x00, 0x01,
0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x43, 0x0d, 0x7f, 0x01, 0x41, 0x80,
0x10, 0x0b, 0x7f, 0x01, 0x41, 0x00, 0x0b, 0x7f, 0x01, 0x41, 0x00, 0x0b,
0x7f, 0x01, 0x41, 0x00, 0x0b, 0x7f, 0x01, 0x41, 0x00, 0x0b, 0x7f, 0x01,
0x41, 0x00, 0x0b, 0x7f, 0x01, 0x41, 0x00, 0x0b, 0x7f, 0x01, 0x41, 0x00,
0x0b, 0x7f, 0x01, 0x41, 0x00, 0x0b, 0x7f, 0x01, 0x41, 0x00, 0x0b, 0x7f,
0x01, 0x41, 0x00, 0x0b, 0x7f, 0x01, 0x41, 0x00, 0x0b, 0x7f, 0x01, 0x41,
0x00, 0x0b, 0x07, 0xdc, 0x01, 0x0c, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72,
0x79, 0x02, 0x00, 0x0c, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e,
0x69, 0x6e, 0x69, 0x74, 0x00, 0x0d, 0x13, 0x24, 0x72, 0x75, 0x6e, 0x74,
0x69, 0x6d, 0x65, 0x2e, 0x77, 0x61, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x49,
0x33, 0x32, 0x00, 0x0e, 0x14, 0x24, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
0x65, 0x2e, 0x77, 0x61, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x52, 0x75, 0x6e,
0x65, 0x00, 0x0f, 0x0f, 0x24, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,
0x2e, 0x77, 0x61, 0x50, 0x75, 0x74, 0x73, 0x00, 0x10, 0x0f, 0x5f, 0x5f,
0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x5f, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x23,
0x31, 0x00, 0x11, 0x0d, 0x5f, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x5f,
0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x12, 0x0d, 0x5f, 0x5f, 0x6d, 0x61,
0x69, 0x6e, 0x5f, 0x5f, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x13, 0x14,
0x73, 0x79, 0x73, 0x63, 0x61, 0x6c, 0x6c, 0x24, 0x61, 0x72, 0x64, 0x75,
0x69, 0x6e, 0x6f, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x14, 0x17, 0x73,
0x79, 0x73, 0x63, 0x61, 0x6c, 0x6c, 0x24, 0x61, 0x72, 0x64, 0x75, 0x69,
0x6e, 0x6f, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x6c, 0x6e, 0x00, 0x15,
0x15, 0x73, 0x79, 0x73, 0x63, 0x61, 0x6c, 0x6c, 0x24, 0x61, 0x72, 0x64,
0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x00, 0x16,
0x06, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x17, 0x0a, 0xcb, 0x07,
0x12, 0x0b, 0x00, 0x23, 0x00, 0x23, 0x00, 0x20, 0x00, 0x6a, 0x24, 0x00,
0x0b, 0x02, 0x00, 0x0b, 0x25, 0x00, 0x20, 0x00, 0x20, 0x00, 0x04, 0x40,
0x20, 0x00, 0x41, 0x01, 0x36, 0x00, 0x00, 0x20, 0x00, 0x20, 0x01, 0x36,
0x00, 0x04, 0x20, 0x00, 0x20, 0x02, 0x36, 0x00, 0x08, 0x20, 0x00, 0x20,
0x03, 0x36, 0x00, 0x0c, 0x0b, 0x0b, 0x06, 0x00, 0x20, 0x00, 0x20, 0x00,
0x0b, 0x16, 0x00, 0x20, 0x00, 0x20, 0x00, 0x04, 0x40, 0x20, 0x00, 0x20,
0x00, 0x28, 0x00, 0x00, 0x41, 0x01, 0x6a, 0x36, 0x00, 0x00, 0x0b, 0x0b,
0x6d, 0x01, 0x05, 0x7f, 0x20, 0x00, 0x41, 0x00, 0x46, 0x04, 0x40, 0x0f,
0x0b, 0x20, 0x00, 0x28, 0x00, 0x00, 0x41, 0x01, 0x6b, 0x21, 0x01, 0x20,
0x01, 0x04, 0x40, 0x20, 0x00, 0x20, 0x01, 0x36, 0x00, 0x00, 0x05, 0x20,
0x00, 0x28, 0x00, 0x08, 0x21, 0x03, 0x20, 0x03, 0x04, 0x40, 0x20, 0x00,
0x28, 0x00, 0x04, 0x21, 0x02, 0x20, 0x02, 0x04, 0x40, 0x20, 0x00, 0x28,
0x00, 0x0c, 0x21, 0x04, 0x20, 0x00, 0x41, 0x10, 0x6a, 0x21, 0x05, 0x03,
0x40, 0x20, 0x05, 0x20, 0x03, 0x11, 0x00, 0x00, 0x20, 0x02, 0x41, 0x01,
0x6b, 0x21, 0x02, 0x20, 0x02, 0x04, 0x40, 0x20, 0x05, 0x20, 0x04, 0x6a,
0x21, 0x05, 0x0c, 0x01, 0x0b, 0x0b, 0x0b, 0x0b, 0x20, 0x00, 0x10, 0x07,
0x0b, 0x0b, 0x2c, 0x00, 0x41, 0x04, 0x10, 0x06, 0x24, 0x03, 0x41, 0x04,
0x10, 0x06, 0x24, 0x04, 0x41, 0x04, 0x10, 0x06, 0x24, 0x05, 0x41, 0x04,
0x10, 0x06, 0x24, 0x07, 0x41, 0x04, 0x10, 0x06, 0x24, 0x08, 0x41, 0x0c,
0x10, 0x06, 0x24, 0x09, 0x41, 0x04, 0x10, 0x06, 0x24, 0x0b, 0x0b, 0x6c,
0x01, 0x03, 0x7f, 0x41, 0x00, 0x21, 0x00, 0x41, 0x00, 0x21, 0x01, 0x41,
0x00, 0x21, 0x02, 0x02, 0x40, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02,
0x40, 0x02, 0x40, 0x20, 0x00, 0x0e, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0b,
0x41, 0x00, 0x21, 0x01, 0x23, 0x0a, 0x21, 0x02, 0x20, 0x02, 0x04, 0x40,
0x0c, 0x02, 0x05, 0x0c, 0x01, 0x0b, 0x0b, 0x41, 0x01, 0x21, 0x01, 0x41,
0x01, 0x24, 0x0a, 0x10, 0x14, 0x23, 0x09, 0x41, 0x00, 0x10, 0x0a, 0x23,
0x09, 0x28, 0x00, 0x00, 0x10, 0x0b, 0x36, 0x00, 0x00, 0x23, 0x09, 0x41,
0x08, 0x36, 0x00, 0x04, 0x23, 0x09, 0x41, 0x07, 0x36, 0x00, 0x08, 0x0c,
0x00, 0x0b, 0x41, 0x02, 0x21, 0x01, 0x0c, 0x02, 0x0b, 0x0b, 0x0b, 0x0b,
0x24, 0x01, 0x02, 0x7f, 0x41, 0x00, 0x21, 0x01, 0x41, 0x00, 0x21, 0x02,
0x02, 0x40, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x20, 0x01, 0x0e, 0x01,
0x00, 0x00, 0x0b, 0x41, 0x00, 0x21, 0x02, 0x0c, 0x02, 0x0b, 0x0b, 0x0b,
0x0b, 0x24, 0x01, 0x02, 0x7f, 0x41, 0x00, 0x21, 0x01, 0x41, 0x00, 0x21,
0x02, 0x02, 0x40, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x20, 0x01, 0x0e,
0x01, 0x00, 0x00, 0x0b, 0x41, 0x00, 0x21, 0x02, 0x0c, 0x02, 0x0b, 0x0b,
0x0b, 0x0b, 0x2a, 0x01, 0x02, 0x7f, 0x41, 0x00, 0x21, 0x02, 0x41, 0x00,
0x21, 0x03, 0x02, 0x40, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x20, 0x02,
0x0e, 0x01, 0x00, 0x00, 0x0b, 0x41, 0x00, 0x21, 0x03, 0x20, 0x00, 0x20,
0x01, 0x10, 0x05, 0x0c, 0x02, 0x0b, 0x0b, 0x0b, 0x0b, 0x49, 0x01, 0x03,
0x7f, 0x41, 0x00, 0x21, 0x00, 0x41, 0x00, 0x21, 0x01, 0x41, 0x00, 0x21,
0x02, 0x02, 0x40, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x20, 0x00, 0x0e,
0x01, 0x00, 0x00, 0x0b, 0x41, 0x00, 0x21, 0x01, 0x23, 0x0b, 0x28, 0x00,
0x00, 0x21, 0x02, 0x20, 0x02, 0x41, 0x01, 0x10, 0x01, 0x41, 0x00, 0x10,
0x0a, 0x41, 0x0f, 0x41, 0x25, 0x10, 0x16, 0x41, 0x00, 0x10, 0x0a, 0x41,
0x34, 0x41, 0x14, 0x10, 0x16, 0x0c, 0x02, 0x0b, 0x0b, 0x0b, 0x0b, 0x74,
0x01, 0x06, 0x7f, 0x41, 0x00, 0x21, 0x00, 0x41, 0x00, 0x21, 0x01, 0x41,
0x00, 0x21, 0x02, 0x41, 0x00, 0x21, 0x03, 0x41, 0x00, 0x21, 0x04, 0x41,
0x00, 0x21, 0x05, 0x02, 0x40, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02,
0x40, 0x20, 0x00, 0x0e, 0x02, 0x00, 0x01, 0x00, 0x0b, 0x41, 0x00, 0x21,
0x01, 0x0c, 0x00, 0x0b, 0x41, 0x01, 0x21, 0x01, 0x23, 0x0b, 0x28, 0x00,
0x00, 0x21, 0x02, 0x23, 0x05, 0x28, 0x00, 0x00, 0x21, 0x03, 0x20, 0x02,
0x20, 0x03, 0x10, 0x02, 0x41, 0xe4, 0x00, 0x10, 0x00, 0x23, 0x0b, 0x28,
0x00, 0x00, 0x21, 0x04, 0x23, 0x03, 0x28, 0x00, 0x00, 0x21, 0x05, 0x20,
0x04, 0x20, 0x05, 0x10, 0x02, 0x41, 0x84, 0x07, 0x10, 0x00, 0x41, 0x01,
0x21, 0x00, 0x0c, 0x01, 0x0b, 0x0b, 0x0b, 0x0b, 0x5f, 0x01, 0x04, 0x7f,
0x41, 0x00, 0x21, 0x00, 0x41, 0x00, 0x21, 0x01, 0x41, 0x00, 0x21, 0x02,
0x41, 0x00, 0x21, 0x03, 0x02, 0x40, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40,
0x02, 0x40, 0x02, 0x40, 0x20, 0x00, 0x0e, 0x03, 0x00, 0x01, 0x02, 0x00,
0x0b, 0x41, 0x00, 0x21, 0x01, 0x23, 0x0c, 0x21, 0x02, 0x20, 0x02, 0x04,
0x40, 0x0c, 0x02, 0x05, 0x0c, 0x01, 0x0b, 0x0b, 0x41, 0x01, 0x21, 0x01,
0x41, 0x01, 0x24, 0x0c, 0x10, 0x14, 0x10, 0x04, 0x21, 0x03, 0x23, 0x0b,
0x20, 0x03, 0x36, 0x00, 0x00, 0x10, 0x11, 0x0c, 0x00, 0x0b, 0x41, 0x02,
0x21, 0x01, 0x0c, 0x02, 0x0b, 0x0b, 0x0b, 0x0b, 0x6f, 0x01, 0x03, 0x7f,
0x41, 0x00, 0x21, 0x00, 0x41, 0x00, 0x21, 0x01, 0x41, 0x00, 0x21, 0x02,
0x02, 0x40, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40,
0x20, 0x00, 0x0e, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0b, 0x41, 0x00, 0x21,
0x01, 0x23, 0x06, 0x21, 0x02, 0x20, 0x02, 0x04, 0x40, 0x0c, 0x02, 0x05,
0x0c, 0x01, 0x0b, 0x0b, 0x41, 0x01, 0x21, 0x01, 0x41, 0x01, 0x24, 0x06,
0x23, 0x03, 0x41, 0x00, 0x36, 0x00, 0x00, 0x23, 0x05, 0x41, 0x01, 0x36,
0x00, 0x00, 0x23, 0x04, 0x41, 0x00, 0x36, 0x00, 0x00, 0x23, 0x08, 0x41,
0x01, 0x36, 0x00, 0x00, 0x23, 0x07, 0x41, 0x02, 0x36, 0x00, 0x00, 0x0c,
0x00, 0x0b, 0x41, 0x02, 0x21, 0x01, 0x0c, 0x02, 0x0b, 0x0b, 0x0b, 0x0b,
0x32, 0x01, 0x02, 0x7f, 0x41, 0x00, 0x21, 0x03, 0x41, 0x00, 0x21, 0x04,
0x02, 0x40, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x20, 0x03, 0x0e, 0x01,
0x00, 0x00, 0x0b, 0x41, 0x00, 0x21, 0x04, 0x20, 0x01, 0x20, 0x02, 0x10,
0x10, 0x41, 0x0a, 0x10, 0x0f, 0x0c, 0x02, 0x0b, 0x0b, 0x0b, 0x20, 0x00,
0x10, 0x0b, 0x0b, 0x2e, 0x01, 0x02, 0x7f, 0x41, 0x00, 0x21, 0x03, 0x41,
0x00, 0x21, 0x04, 0x02, 0x40, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x20,
0x03, 0x0e, 0x01, 0x00, 0x00, 0x0b, 0x41, 0x00, 0x21, 0x04, 0x20, 0x01,
0x20, 0x02, 0x10, 0x10, 0x0c, 0x02, 0x0b, 0x0b, 0x0b, 0x20, 0x00, 0x10,
0x0b, 0x0b, 0x08, 0x00, 0x10, 0x0c, 0x10, 0x13, 0x10, 0x12, 0x0b, 0x0b,
0x4e, 0x01, 0x00, 0x41, 0x00, 0x0b, 0x48, 0x24, 0x24, 0x77, 0x61, 0x64,
0x73, 0x24, 0x24, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0xe5, 0x87,
0xb9, 0xe8, 0xaf, 0xad, 0xe8, 0xa8, 0x80, 0x28, 0x57, 0x61, 0x29, 0x2f,
0x41, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x20, 0x69, 0x73, 0x20, 0x72,
0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x2e, 0x2e, 0x2e, 0x0a, 0x68,
0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x61, 0x2d, 0x6c, 0x61,
0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x0a
};
unsigned int app_wasm_len = 1543;

View File

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

View File

@ -1,8 +0,0 @@
# 版权 @2023 凹语言 作者。保留所有权利。
default:
go run ../../main.go yacc -l -p=expr -c="copyright.txt" -o="y.wa" expr.y
go run ../../main.go y.wa
clean:
-rm y.* a.out*

View File

@ -1,8 +0,0 @@
:: 版权 @2023 凹语言 作者。保留所有权利。
setlocal
cd %~dp0
go run ../../main.go yacc -l -p=expr -c="copyright.txt" -o="y.wa" expr.y
go run ../../main.go "y.wa"

View File

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

View File

@ -1,5 +0,0 @@
// 版权 @2022 _examples/hello 作者。保留所有权利。
func 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,89 +0,0 @@
// 版权 @2021 凹语言 作者。保留所有权利。
type S1 struct {
a: i32
}
type S2 struct {
b: i32
}
type I1 interface {
f()
}
type I2 interface {
f2()
}
func S1.f() {
println("This is S1, this.a==", this.a)
}
func S2.f(){
println("This is S2, this.b==", this.b)
}
func main() {
v1 := S1{a: 13}
var i1: I1 = &v1 //具体类型到具名接口
v1.f() //直接调用
i1.f() //接口调用
doConcreteType(i1)
i1.f()
v2 := S2{b: 42}
i1 = &v2 //具体类型到具名接口
i1.f()
doConcreteType(i1)
i1.f()
var ni: interface{} = &v1 //具体类型到空接口
i1 = ni.(I1) //接口动态互转
i1.f()
ni = &v2 //具体类型到空接口
i1 = ni.(I1) //接口动态互转
i1.f()
var ival: i32 = 777
ni = ival
doConcreteType(ni)
doConcreteType(v1)
doConcreteType(v2)
doConcreteType("你好凹语言")
//i2 := ni.(I2) //接口互转由于v2未实现I2这会触发异常
//i2.f2()
var anoi: interface{ f() } = &v1 //具体类型到匿名接口
doConcreteType(anoi) //匿名接口向具名接口转换
anoi.f()
}
func doConcreteType(i: interface{}) {
//接口到具体类型断言
switch c := i.(type){
case *S1:
println("*S1")
c.a *= 2
case *S2:
println("*S2")
c.b *= 2
case i32:
println("i32: ", c)
case string:
println("string: ", c)
case S1:
println("S1, S1.a==", c.a)
case S2:
println("S2, S2.b==", c.b)
}
}

View File

@ -1,18 +0,0 @@
// 版权 @2022 凹语言 作者。保留所有权利。
func main {
test_array(2, 4)
test_array(7, 9)
}
func 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 凹语言 作者。保留所有权利。
func 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()
}
func bye() {
println("再见!\nbye!")
}
func test_calc0(a i32, b i32, c i32) i32 {
return (-a) * 5 / (b - c + 2)
}
func test_calc1(a i32, b i32, c i32) i32 {
return test_calc0(a, b, c)
}
func test_calc2(a f64, b f64, c f64) f64 {
return (-a) * 5 / (b - c + 2)
}
func test_calc3(a f64, b f64, c f64) f64 {
return test_calc2(a, b, c)
}
func test_calc4(a u16, b u16, c u16) u16 {
return (-a) * 5 / (b - c + 2)
}
func test_calc5(a u16, b u16, c u16) u16 {
return test_calc4(-a, b, c)
}
func test_cmp0(a u16, b u16) {
if a > b {
println(a, " > ", b)
} else {
println(a, " <= ", b)
}
}
func test_cmp1(a i64, b i64) {
if a <= b {
println(a, " <= ", b)
} else {
println(a, " > ", b)
}
}
func test_cmp2(a f64, b f64) {
if a != b {
println(a, " != ", b)
} else {
println(a, " == ", b)
}
}
func test_jmp(a i32) {
for {
if a > 10 {
return
}
println(a)
a++
}
}
func test_loop0(a i16) {
for i := i16(0); i < a; i++ {
println(i, " * ", i, " = ", i * i)
}
}
func 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)
}
}
}
func 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
}
func 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])
}
}
func 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
func test_struct2() {
for i := 0; i < 16; i++ {
st0.arr0[i] = i * i
st0.arr1[i] = f32(i) * 2.0
}
}
func getst0int(st0 struct_t0, i int) int {
return st0.arr0[i]
}
func getst0f32(st0 *struct_t0, i int) f32 {
return st0.arr1[i]
}
func test_struct3() {
for i := 6; i < 14; i += 2 {
println(getst0int(st0, i), ", ", getst0f32(&st0, i + 1))
}
}
func 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
}
func 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
}
func 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
func test_array2() {
for i := 0; i < 32; i++ {
arr0[i] = fff32(i * i)
}
}
func getarr0a(arr [32]fff32, i int) fff32 {
return arr[i]
}
func getarr0b(arr *[32]fff32, i int) fff32 {
return arr[i]
}
func makearr0a(i int) [32]fff32 {
var r [32]fff32
for j := 0; j < 32; j++ {
r[j] = fff32(i * j)
}
return r
}
func makearr0b(i int) *[32]fff32 {
for j := 0; j < 32; j++ {
arr1[j] = 2000 - fff32(i * j)
}
return &arr1
}
func test_array3() {
for i := 6; i < 20; i += 2 {
println(getarr0a(arr0, i), ", ", getarr0b(&arr0, i + 1))
}
}
func test_array4() {
r0, r1 := makearr0a(10), makearr0b(20)
for i := 6; i < 20; i += 2 {
println(r0[i], ", ", r1[i])
}
}
func convert_i32_to_i16(a i32) i16 {
return i16(a)
}
func convert_i32_to_u16(a i32) u16 {
return u16(a)
}
func convert_i16_to_i32(a i16) i32 {
return i32(a)
}
func convert_u16_to_i32(a u16) i32 {
return i32(a)
}
func 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))
}
func convert_f64_to_f32(a f64) f32 {
return f32(a)
}
func test_convert1() {
println(f64(convert_f64_to_f32(3.1415926535)))
}
func convert_i16_to_f64(a i16) f64 {
return f64(a)
}
func convert_u16_to_f64(a u16) f64 {
return f64(a)
}
func 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))
}
func convert_f64_to_i32(a f64) i32 {
return i32(a)
}
func convert_f64_to_u32(a f64) u32 {
return u32(a)
}
func 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))
}
func 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
func 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}
func test_global_variables_0() {
println("gv0: {", gv0.v0, ", ", gv0.v1, "}")
println("gv1: {", gv1[0], ", ", gv1[1], ", ", gv1[2], ", ", gv1[3], "}")
}
func 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
func get_int_addr(a int) *int {
if a > 0 {
return &gint0
} else {
return &gint1
}
}
func set_int(a *int) {
*a += 10
}
func test_pointer(a int) {
println(gint0, ", ", gint1)
p := get_int_addr(a)
set_int(p)
println(gint0, ", ", gint1)
}
func getPi() f32 {
return 3.1415926535
}
func getE() f32 {
return 2.71828
}
func minusf32(a f32) f32 {
return 0 - a
}
func circle_area(r f32) f32 {
return r * r * 3.1415926
}
func 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 +0,0 @@
版权 @2022 _examples/hello 作者。保留所有权利。

View File

@ -1,5 +0,0 @@
// 版权 @2022 _examples/hello 作者。保留所有权利。
func 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,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

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

View File

@ -1,18 +0,0 @@
build:
-@rm ./web/*.wasm
#go run ../../main.go fmt ./src/main.wa
#go run ../../main.go fmt ./src/canvas/canvas.wa
go run ../../main.go build -o ./web/snake.wasm .
run:
make build
cd web && python3 -m http.server
publish:
make build
-rm -rf ../../docs/snake/
mkdir -p ../../docs/snake
cp ./web/* ../../docs/snake/
clean:

View File

@ -1,3 +0,0 @@
wa build _examples/snake
wat2wasm a.out.wat
copy a.out.wasm _examples/snake/web/snake.wasm

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,6 +11,7 @@ import (
"wa-lang.org/wa/internal/format"
"wa-lang.org/wa/internal/loader"
"wa-lang.org/wa/internal/logger"
"wa-lang.org/wa/internal/wamime"
)
// 调试参数
@ -96,9 +97,14 @@ func BuildVFS(cfg *config.Config, vfs *config.PkgVFS, appPkg string) (wat []byte
// 格式化代码
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,27 +6,27 @@
package api
import (
"os"
"wa-lang.org/wa/internal/app/apputil"
"wa-lang.org/wa/internal/config"
"wa-lang.org/wa/internal/wabt"
"wa-lang.org/wa/internal/wazero"
)
// 执行凹代码
func RunCode(cfg *config.Config, filename, code string, arg ...string) (stdoutStderr []byte, err error) {
func RunCode(cfg *config.Config, filename, code string, args ...string) (stdoutStderr []byte, err error) {
// 编译为 wat 格式
wat, err := BuildFile(cfg, filename, code)
// 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(cfg, outfile, arg...)
// 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

@ -11,7 +11,7 @@ import (
func ExampleRunCode() {
const code = `
var gBase: i32 = 1000
global gBase: i32 = 1000
func main() {
println(add(40, 2) + gBase)
@ -56,6 +56,31 @@ func ExampleRunCode_args() {
fmt.Print(string(output))
// Output:
// 0:aa
// 1:bb
// 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

@ -31,7 +31,7 @@ func main() {
}
const code = `
func main() {
func main {
println(add(40, 2))
}
@ -40,11 +40,10 @@ func add(a: i32, b: i32) => i32 {
}
`
const code_zh = `// 版权 @2022 _examples/hello 作者。保留所有权利。
const code_zh = `
引于 "书"
·"你好,凹语言"
·"你好,凹语言中文版"
`

View File

@ -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.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -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,4 +1,5 @@
<!--
<!--
// 版权 @2019 凹语言 作者。保留所有权利。
// https://wa-lang.org
-->

Before

Width:  |  Height:  |  Size: 628 B

After

Width:  |  Height:  |  Size: 628 B

View File

@ -27,7 +27,7 @@
我们计划在完成凹中文前端的重构即完全脱离现有的Go前端之时得到一套稳定的中文语法。
现在可运行的示例,请参考凹语言工程中的[可执行示例](https://gitee.com/wa-lang/wa/tree/frontend_wz/_examples/wz/)。
现在可运行的示例,请参考凹语言工程中的[可执行示例](https://gitee.com/wa-lang/wa/tree/frontend_wz/waroot/examples/wz/)。
## 简单示例
@ -545,7 +545,7 @@ func Point.Length() => int {
return math.sqrt(this.x*this.x + this.y*this.y)
}
fn main {
func main {
p := Point{x:1, y:2}
println(p.Length())
}
@ -777,4 +777,4 @@ type duck interface {
届时就可以考虑给中文语法扩充更贴近中文用户使用习惯的特殊新语法了。
凹中文版的目标,不是让人人都用中文版语法、抛弃英文版语法,而是想抛砖引玉,启发所有人都来设计与开发更适合国人的编程语言。
凹中文版的目标,不是让人人都用中文版语法、抛弃英文版语法,而是想抛砖引玉,启发所有人都来设计与开发更适合国人的编程语言。

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 初始化和执行顺序

3
go.mod
View File

@ -5,6 +5,7 @@ module wa-lang.org/wa
go 1.17
require (
github.com/tetratelabs/wazero v1.0.0-pre.4
github.com/BurntSushi/toml v1.3.2
wa-lang.org/wabt-go v1.3.0
wa-lang.org/wazero v1.0.1
)

4
go.sum
View File

@ -1,6 +1,10 @@
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,60 +0,0 @@
// 版权 @2019 凹语言 作者。保留所有权利。
package app
import (
"os/exec"
"runtime"
"wa-lang.org/wa/internal/config"
"wa-lang.org/wa/internal/logger"
)
// 命令行程序对象
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 = config.WaOS_Default
}
if p.opt.TargetArch == "" {
p.opt.TargetArch = config.WaArch_Default
}
return p
}
func (p *App) GetConfig() *config.Config {
return p.opt.Config()
}

View File

@ -1,19 +0,0 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package app
import (
"wa-lang.org/wa/internal/ast"
"wa-lang.org/wa/internal/parser"
"wa-lang.org/wa/internal/token"
)
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)
}

View File

@ -1,23 +0,0 @@
// 版权 @2019 凹语言 作者。保留所有权利。
package app
import (
"wa-lang.org/wa/internal/backends/compiler_c"
"wa-lang.org/wa/internal/loader"
)
func (p *App) CIR(filename string) error {
cfg := p.opt.Config()
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
}

View File

@ -1,35 +0,0 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package app
import (
"os"
"strings"
"wa-lang.org/wa/internal/format"
)
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)
}

View File

@ -1,32 +0,0 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package app
import (
"fmt"
"wa-lang.org/wa/internal/scanner"
"wa-lang.org/wa/internal/token"
)
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
}

View File

@ -1,143 +0,0 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package app
import (
"bytes"
"fmt"
"os"
"strings"
"time"
"github.com/tetratelabs/wazero/sys"
"wa-lang.org/wa/internal/app/apputil"
"wa-lang.org/wa/internal/backends/compiler_wat"
"wa-lang.org/wa/internal/loader"
)
func (p *App) RunTest(pkgpath string, appArgs ...string) error {
cfg := p.opt.Config()
cfg.UnitTest = true
prog, err := loader.LoadProgram(cfg, pkgpath)
if err != nil {
return err
}
startTime := time.Now()
mainPkg := prog.Pkgs[prog.Manifest.MainPkg]
if len(mainPkg.TestInfo.Files) == 0 {
fmt.Printf("? %s [no test files]\n", prog.Manifest.MainPkg)
return nil
}
var firstError error
for _, t := range mainPkg.TestInfo.Tests {
output, err := compiler_wat.New().Compile(prog, t.Name)
if err != nil {
return err
}
if err = os.WriteFile("a.out.wat", []byte(output), 0666); err != nil {
return err
}
stdout, stderr, err := apputil.RunWasmEx(cfg, "a.out.wat", appArgs...)
stdout = bytes.TrimSpace(stdout)
bOutputOK := t.Output == string(stdout)
if err == nil && bOutputOK {
continue
}
if err != nil {
if firstError == nil {
firstError = err
}
if _, ok := err.(*sys.ExitError); ok {
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
if s := sWithPrefix(string(stdout), " "); s != "" {
fmt.Println(s)
}
if s := sWithPrefix(string(stderr), " "); s != "" {
fmt.Println(s)
}
} else {
fmt.Println(err)
}
}
if t.Output != "" {
if expect, got := t.Output, string(stdout); expect != got {
if firstError == nil {
firstError = fmt.Errorf("expect = %q, got = %q", expect, got)
}
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
fmt.Printf(" expect = %q, got = %q\n", expect, got)
}
}
}
for _, t := range mainPkg.TestInfo.Examples {
output, err := compiler_wat.New().Compile(prog, t.Name)
if err != nil {
return err
}
if err = os.WriteFile("a.out.wat", []byte(output), 0666); err != nil {
return err
}
stdout, stderr, err := apputil.RunWasmEx(cfg, "a.out.wat", appArgs...)
stdout = bytes.TrimSpace(stdout)
bOutputOK := t.Output == string(stdout)
if err == nil && bOutputOK {
continue
}
if err != nil {
if firstError == nil {
firstError = err
}
if _, ok := err.(*sys.ExitError); ok {
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
if s := sWithPrefix(string(stdout), " "); s != "" {
fmt.Println(s)
}
if s := sWithPrefix(string(stderr), " "); s != "" {
fmt.Println(s)
}
} else {
fmt.Println(err)
}
}
if t.Output != "" {
if expect, got := t.Output, string(stdout); expect != got {
if firstError == nil {
firstError = fmt.Errorf("expect = %q, got = %q", expect, got)
}
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
fmt.Printf(" expect = %q, got = %q\n", expect, got)
}
}
}
if firstError != nil {
fmt.Printf("FAIL %s %v\n", prog.Manifest.MainPkg, time.Now().Sub(startTime).Round(time.Millisecond))
os.Exit(1)
}
fmt.Printf("ok %s %v\n", prog.Manifest.MainPkg, time.Now().Sub(startTime).Round(time.Millisecond))
return nil
}
func sWithPrefix(s, prefix string) string {
lines := strings.Split(strings.TrimSpace(s), "\n")
for i, line := range lines {
lines[i] = prefix + strings.TrimSpace(line)
}
return strings.Join(lines, "\n")
}

View File

@ -1,34 +0,0 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package app
import (
"os"
"sort"
"wa-lang.org/wa/internal/loader"
"wa-lang.org/wa/internal/ssa"
)
func (p *App) SSA(filename string) error {
cfg := p.opt.Config()
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
}

View File

@ -1,40 +0,0 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package app
import (
"bytes"
"errors"
"io"
"os"
"strings"
)
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

@ -1,46 +0,0 @@
// 版权 @2019 凹语言 作者。保留所有权利。
package app
import (
"fmt"
"os"
"strings"
"wa-lang.org/wa/internal/backends/compiler_wat"
"wa-lang.org/wa/internal/loader"
)
func (p *App) WASM(filename string) ([]byte, error) {
if _, err := os.Lstat(filename); err != nil {
return nil, fmt.Errorf("%q not found", filename)
}
cfg := p.opt.Config()
prog, err := loader.LoadProgram(cfg, filename)
if err != nil {
return nil, err
}
// 凹中文的源码启动函数为【启】对应的wat函数名应当是"$0xe590af"
main := "main"
if strings.HasSuffix(filename, ".wz") {
main = "$0xe590af"
}
// 如果是运行整个package则判断主包里是否有名为【启】的函数如果有则将其作为启动函数
if filename == "." {
for k := range prog.SSAMainPkg.Members {
if k == "启" && prog.SSAMainPkg.Members[k].Type().Underlying().String() == "func()" {
main = "$0xe590af"
}
}
}
output, err := compiler_wat.New().Compile(prog, main)
if err != nil {
return nil, err
}
return []byte(output), nil
}

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
}

View File

@ -0,0 +1,49 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appdoc
import (
"fmt"
"os"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app/appbase"
"wa-lang.org/wa/internal/config"
"wa-lang.org/wa/internal/loader"
)
var CmdDoc = &cli.Command{
Hidden: true,
Name: "doc",
Usage: "show documentation for package or symbol",
ArgsUsage: "name...",
Flags: []cli.Flag{
appbase.MakeFlag_target(),
appbase.MakeFlag_tags(),
},
Action: func(c *cli.Context) error {
opt := appbase.BuildOptions(c)
var pkgpath = "."
var names []string
if c.Args().Len() > 0 {
pkgpath = c.Args().First()
}
if c.Args().Len() > 1 {
names = c.Args().Slice()[1:]
}
RunDoc(opt.Config(), pkgpath, names...)
return nil
},
}
func RunDoc(cfg *config.Config, pkgpath string, names ...string) {
prog, err := loader.LoadProgram(cfg, pkgpath)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
doc := BuildPkgDoc(prog)
doc.Show(names...)
}

View File

@ -0,0 +1,71 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appdoc
import (
"fmt"
"log"
"wa-lang.org/wa/internal/loader"
"wa-lang.org/wa/internal/types"
)
type PkgDoc struct {
Prog *loader.Program
Consts []*types.Const
Types []*types.TypeName
Globals []*types.Var
Funcs []*types.Func
}
func BuildPkgDoc(prog *loader.Program) (p *PkgDoc) {
p = &PkgDoc{Prog: prog}
p.buildDoc()
return p
}
func (p *PkgDoc) Show(names ...string) {
if len(names) != 0 {
fmt.Println("TODO:", names)
return
}
for _, c := range p.Consts {
// typ := c.Type().(*types.Basic)
fmt.Printf("const %s %v\n", c.Name(), c.Type())
}
for _, c := range p.Globals {
fmt.Printf("global %s %v\n", c.Name(), c.Type())
}
for _, fn := range p.Funcs {
sig := fn.Type().(*types.Signature)
if sig.Results().Len() > 0 {
fmt.Printf("func %s%v => %v\n", fn.Name(), sig.Params(), sig.Results())
} else {
fmt.Printf("func %s%v\n", fn.Name(), sig.Params())
}
}
}
func (p *PkgDoc) buildDoc() {
mainPkg := p.Prog.Pkgs[p.Prog.Manifest.MainPkg]
scope := mainPkg.Pkg.Scope()
for _, s := range scope.Names() {
if obj := scope.Lookup(s); obj.Exported() {
switch x := obj.(type) {
case *types.Const:
p.Consts = append(p.Consts, x)
case *types.TypeName:
p.Types = append(p.Types, x)
case *types.Var:
p.Globals = append(p.Globals, x)
case *types.Func:
p.Funcs = append(p.Funcs, x)
default:
log.Fatalf("unknown %[1]T %[1]v\n", obj)
}
}
}
}

View File

@ -0,0 +1,138 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appfmt
import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app/appbase"
"wa-lang.org/wa/internal/config"
"wa-lang.org/wa/internal/format"
)
var CmdFmt = &cli.Command{
Name: "fmt",
Usage: "format Wa source code file",
ArgsUsage: "[<file.wa>|<path>|<path>/...]",
Action: func(c *cli.Context) error {
for _, path := range c.Args().Slice() {
if err := Fmt(path); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
return nil
},
}
func Fmt(path string) error {
if appbase.IsNativeFile(path, ".wa", ".wz") {
_, err := fmtFile(path)
return err
}
if path == "" {
if _, err := os.Lstat(config.WaModFile); err == nil {
path = "./..."
} else if _, err := os.Lstat(config.WaModFile + ".json"); err == nil {
path = "./..."
} else {
path = "."
}
}
if !filepath.IsAbs(path) && !strings.HasPrefix(path, ".") {
return fmt.Errorf("%q is not valid path", path)
}
var waFileList []string
switch {
case strings.HasSuffix(path, ".wa"):
waFileList = append(waFileList, path)
case strings.HasSuffix(path, ".wz"):
waFileList = append(waFileList, path)
case strings.HasSuffix(path, "/..."):
waFileList = getDirWaFileList(
strings.TrimSuffix(path, "..."),
true, ".wa", ".wz", // 包含子目录
)
default:
// 不包含子目录
waFileList = getDirWaFileList(
path, false, ".wa", ".wz",
)
}
var changedFileList []string
for _, s := range waFileList {
changed, err := fmtFile(s)
if err != nil {
return fmt.Errorf("%s: %w", s, err)
}
if changed {
changedFileList = append(changedFileList, s)
}
}
for _, s := range changedFileList {
fmt.Println(s)
}
return nil
}
func fmtFile(path string) (changed bool, err error) {
code, changed, err := format.File(nil, path, nil)
if err != nil {
return false, err
}
if changed {
if err = os.WriteFile(path, code, 0666); err != nil {
return false, err
}
}
return changed, nil
}
func getDirWaFileList(dir string, walkSubDir bool, extList ...string) []string {
var waFileList []string
if !walkSubDir {
files, err := os.ReadDir(".")
if err != nil {
return nil
}
for _, file := range files {
if file.IsDir() {
continue
}
for _, ext := range extList {
if strings.HasSuffix(file.Name(), ext) {
waFileList = append(waFileList, filepath.Join(dir, file.Name()))
}
}
}
sort.Strings(waFileList)
return waFileList
}
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
for _, ext := range extList {
if strings.HasSuffix(path, ext) {
waFileList = append(waFileList, path)
return nil
}
}
return nil
})
sort.Strings(waFileList)
return waFileList
}

View File

@ -1,6 +1,6 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package app
package appinit
import (
"fmt"
@ -10,13 +10,55 @@ import (
"text/template"
"time"
"wa-lang.org/wa/internal/waroot"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app/appbase"
"wa-lang.org/wa/waroot"
)
func (p *App) InitApp(name, pkgpath string, update bool) error {
var CmdInit = &cli.Command{
Name: "init",
Usage: "init a sketch Wa module",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Usage: "set app name",
Value: "hello",
},
&cli.StringFlag{
Name: "pkgpath",
Aliases: []string{"p"},
Usage: "set pkgpath file",
Value: "myapp",
},
&cli.BoolFlag{
Name: "update",
Aliases: []string{"u"},
Usage: "update example",
},
},
Action: func(c *cli.Context) error {
err := InitApp(c.String("name"), c.String("pkgpath"), c.Bool("update"))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}
func InitApp(name, pkgpath string, update bool) error {
if name == "" {
return fmt.Errorf("init failed: <%s> is empty", name)
}
if !appbase.IsValidAppName(name) {
return fmt.Errorf("init failed: <%s> is invalid name", name)
}
if !appbase.IsValidPkgpath(pkgpath) {
return fmt.Errorf("init failed: <%s> is invalid pkgpath", pkgpath)
}
if !update {
if _, err := os.Lstat(name); err == nil {

View File

@ -0,0 +1,58 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package applex
import (
"fmt"
"os"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app/appbase"
"wa-lang.org/wa/internal/scanner"
"wa-lang.org/wa/internal/token"
)
var CmdLex = &cli.Command{
Hidden: true,
Name: "lex",
Usage: "lex Wa source code and print token list",
Action: func(c *cli.Context) error {
if c.NArg() == 0 {
fmt.Fprintf(os.Stderr, "no input file")
os.Exit(1)
}
err := Lex(c.Args().First())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}
func Lex(filename string) error {
if !appbase.IsNativeFile(filename, ".wa", ".wz") {
return fmt.Errorf("%q is not valid path", filename)
}
src, err := os.ReadFile(filename)
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
}

View File

@ -1,6 +1,6 @@
// 版权 @2019 凹语言 作者。保留所有权利。
package app
package appllvm
import (
"fmt"
@ -9,12 +9,59 @@ import (
"path"
"strings"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app/appbase"
"wa-lang.org/wa/internal/backends/compiler_llvm"
"wa-lang.org/wa/internal/config"
"wa-lang.org/wa/internal/loader"
)
func (p *App) LLVM(infile string, outfile string, target string, debug bool) error {
cfg := p.opt.Config()
var CmdNative = &cli.Command{
Hidden: true,
Name: "native",
Usage: "compile Wa source code to native executable",
Flags: []cli.Flag{
appbase.MakeFlag_output(),
appbase.MakeFlag_target(),
appbase.MakeFlag_tags(),
&cli.BoolFlag{
Name: "debug",
Usage: "dump orginal intermediate representation",
},
&cli.StringFlag{
Name: "clang",
Usage: "set llvm/clang path",
},
&cli.StringFlag{
Name: "llc",
Usage: "set llvm/llc path",
},
},
Action: func(c *cli.Context) error {
outfile := c.String("output")
target := c.String("target")
debug := c.Bool("debug")
infile := ""
if c.NArg() == 0 {
fmt.Fprintf(os.Stderr, "no input file")
os.Exit(1)
}
infile = c.Args().First()
opt := appbase.BuildOptions(c, config.WaBackend_llvm)
if err := LLVMRun(opt, infile, outfile, target, debug); err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}
func LLVMRun(opt *appbase.Option, infile string, outfile string, target string, debug bool) error {
cfg := opt.Config()
instat, err := os.Stat(infile)
if err != nil {
@ -75,7 +122,7 @@ func (p *App) LLVM(infile string, outfile string, target string, debug bool) err
llc = append(llc, "-mcpu=atmega328")
default:
}
cmd0 := exec.Command(p.opt.Llc, llc...)
cmd0 := exec.Command(opt.Llc, llc...)
cmd0.Stderr = os.Stderr
if err := cmd0.Run(); err != nil {
fmt.Fprintf(os.Stderr, "**** failed to invoke LLVM ****\n")
@ -116,10 +163,10 @@ func (p *App) LLVM(infile string, outfile string, target string, debug bool) err
if target != "" {
clangArgs = append(clangArgs, "-target", target)
}
if p.opt.Debug {
if opt.Debug {
clangArgs = append(clangArgs, "-v")
}
cmd1 := exec.Command(p.opt.Clang, clangArgs...)
cmd1 := exec.Command(opt.Clang, clangArgs...)
cmd1.Stderr = os.Stderr
cmd1.Stdout = os.Stdout
if err := cmd1.Run(); err != nil {

View File

@ -0,0 +1,29 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package applogo
import "wa-lang.org/wa/internal/3rdparty/cli"
var CmdLogo = &cli.Command{
Name: "logo",
Usage: "print Wa text format logo",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "more",
Aliases: []string{"m"},
Usage: "print more text logos",
},
&cli.BoolFlag{
Name: "svg",
Usage: "print svg logo",
},
},
Action: func(c *cli.Context) error {
if c.Bool("svg") {
PrintLogoSvg()
return nil
}
PrintLogo(c.Bool("more"))
return nil
},
}

View File

@ -1,12 +1,16 @@
// 版权 @2019 凹语言 作者。保留所有权利。
package app
package applogo
import (
"fmt"
"time"
)
func PrintLogoSvg() {
fmt.Print(logoSvg)
}
func PrintLogo(more bool) {
if is1024Day() {
fmt.Print(logo1024)
@ -45,6 +49,39 @@ const logo1024 = `
+------------+
`
const logoSvg = `<!--
// 版权 @2019 凹语言 作者。保留所有权利。
// https://wa-lang.org
-->
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 400 400" width="400" height="400"
style="border: 0px solid red"
>
<path
stroke="none" fill="LightSeaGreen"
d="M60,50 h90 v100 h100 v-100 h90 l10,10 v280 l-10,10 h-280 l-10,-10 v-280"
/>
<path
stroke="none" fill="white"
d="M100,100 m-5,-5 h10 v10 h-10"
/>
<path
stroke="none" fill="white"
d="M400,100 m-100,0 m-5,-5 h10 v10 h-10"
/>
<path
stroke="white" fill="none" stroke-width="8" stroke-linecap="round"
d="M200,230 l34,34 l34,-34 M200,230 l-34,34 l-34,-34"
/>
</svg>
`
const moreLogos = `
+---+ +---+
| * | | * |

View File

@ -0,0 +1,23 @@
package applsp
import (
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/lsp"
)
var CmdLsp = &cli.Command{
Hidden: true,
Name: "lsp",
Usage: "run Wa langugage server",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "log-file",
Usage: "set log file",
Value: "",
},
},
Action: func(c *cli.Context) error {
lsp.NewLSPServer(&lsp.Option{}).Run()
return nil
},
}

View File

@ -0,0 +1,82 @@
<!doctype html>
<html>
<head>
<link rel="icon" href="/static/logo.svg">
<title>凹语言游乐场</title>
<link rel="stylesheet" href="/static/playground/playground-full.css">
<script src="/static/playground/jquery/1.8.2/jquery.min.js"></script>
<script src="/static/playground/playground-full.js"></script>
<style>
.cm-tab {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);
background-position: right;
background-repeat: no-repeat;
}
</style>
<script>
$(document).ready(function() {
playground({
'theme': 'default',
'codeEl': '#code',
'outputEl': '#output',
'runEl': '#run',
'fmtEl': '#fmt',
'enableHistory': true
});
// Avoid line wrapping.
var about = $('#about');
about.click(function(e) {
if ($(e.target).is('a')) {
return;
}
about.hide();
});
$('#homeButton').click(function() {
$(location).attr('href','/')
})
$('#aboutButton').click(function() {
if (about.is(':visible')) {
about.hide();
return;
}
about.show();
})
// Fire Google Analytics events for Run/Share button clicks.
if (window.trackEvent) {
$('#run').click(function() {
window.trackEvent('playground', 'click', 'run-button');
});
$('#fmt').click(function() {
window.trackEvent('playground', 'click', 'fmt-button');
});
}
});
</script>
</head>
<body itemscope itemtype="http://schema.org/CreativeWork">
<div id="banner">
<div id="head" itemprop="name">凹语言游乐场</div>
<div id="controls">
<input type="button" value="运行" id="run">
<input type="button" value="格式化" id="fmt">
</div>
<div id="aboutControls">
<input type="button" value="关于" id="aboutButton">
</div>
</div>
<div id="wrap">
<textarea itemprop="description" id="code" name="code" autocorrect="off" autocomplete="off" autocapitalize="off" spellcheck="false">{{printf "%s" .Snippet.Body}}</textarea>
</div>
<div id="output"></div>
<div id="about">
<p><b>凹语言 (The Wa Programming Language)</b></p>
<a target="_blank" href="https://wa-lang.org">https://wa-lang.org</a>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,31 @@
<!--
// 版权 @2019 凹语言 作者。保留所有权利。
// https://wa-lang.org
-->
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 400 400" width="400" height="400"
style="border: 0px solid red"
>
<path
stroke="none" fill="LightSeaGreen"
d="M60,50 h90 v100 h100 v-100 h90 l10,10 v280 l-10,10 h-280 l-10,-10 v-280"
/>
<path
stroke="none" fill="white"
d="M100,100 m-5,-5 h10 v10 h-10"
/>
<path
stroke="none" fill="white"
d="M400,100 m-100,0 m-5,-5 h10 v10 h-10"
/>
<path
stroke="white" fill="none" stroke-width="8" stroke-linecap="round"
d="M200,230 l34,34 l34,-34 M200,230 l-34,34 l-34,-34"
/>
</svg>

After

Width:  |  Height:  |  Size: 628 B

View File

@ -0,0 +1,3 @@
build:
cat codemirror.js codemirror-wa.js playground.js | uglifyjs > playground-full.js && \
cat style.css codemirror.css codemirror-*.css > playground-full.css

View File

@ -0,0 +1,38 @@
/*
Name: Base16 Default Light
Author: Chris Kempson (http://chriskempson.com)
CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
*/
.cm-s-base16-light.CodeMirror { background: #f5f5f5; color: #202020; }
.cm-s-base16-light div.CodeMirror-selected { background: #e0e0e0; }
.cm-s-base16-light .CodeMirror-line::selection, .cm-s-base16-light .CodeMirror-line > span::selection, .cm-s-base16-light .CodeMirror-line > span > span::selection { background: #e0e0e0; }
.cm-s-base16-light .CodeMirror-line::-moz-selection, .cm-s-base16-light .CodeMirror-line > span::-moz-selection, .cm-s-base16-light .CodeMirror-line > span > span::-moz-selection { background: #e0e0e0; }
.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 0px; }
.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; }
.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; }
.cm-s-base16-light .CodeMirror-linenumber { color: #b0b0b0; }
.cm-s-base16-light .CodeMirror-cursor { border-left: 1px solid #505050; }
.cm-s-base16-light span.cm-comment { color: #8f5536; }
.cm-s-base16-light span.cm-atom { color: #aa759f; }
.cm-s-base16-light span.cm-number { color: #aa759f; }
.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute { color: #90a959; }
.cm-s-base16-light span.cm-keyword { color: #ac4142; }
.cm-s-base16-light span.cm-string { color: #f4bf75; }
.cm-s-base16-light span.cm-variable { color: #90a959; }
.cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; }
.cm-s-base16-light span.cm-def { color: #d28445; }
.cm-s-base16-light span.cm-bracket { color: #202020; }
.cm-s-base16-light span.cm-tag { color: #ac4142; }
.cm-s-base16-light span.cm-link { color: #aa759f; }
.cm-s-base16-light span.cm-error { background: #ac4142; color: #505050; }
.cm-s-base16-light .CodeMirror-activeline-background { background: #DDDCDC; }
.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

View File

@ -0,0 +1,53 @@
/*
Name: material
Author: Michael Kaminsky (http://github.com/mkaminsky11)
Original material color scheme by Mattia Astorino (https://github.com/equinusocio/material-theme)
*/
.cm-s-material.CodeMirror {
background-color: #263238;
color: rgba(233, 237, 237, 1);
}
.cm-s-material .CodeMirror-gutters {
background: #263238;
color: rgb(83,127,126);
border: none;
}
.cm-s-material .CodeMirror-guttermarker, .cm-s-material .CodeMirror-guttermarker-subtle, .cm-s-material .CodeMirror-linenumber { color: rgb(83,127,126); }
.cm-s-material .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }
.cm-s-material div.CodeMirror-selected { background: rgba(255, 255, 255, 0.15); }
.cm-s-material.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }
.cm-s-material .CodeMirror-line::selection, .cm-s-material .CodeMirror-line > span::selection, .cm-s-material .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }
.cm-s-material .CodeMirror-line::-moz-selection, .cm-s-material .CodeMirror-line > span::-moz-selection, .cm-s-material .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }
.cm-s-material .CodeMirror-activeline-background { background: rgba(0, 0, 0, 0); }
.cm-s-material .cm-keyword { color: rgba(199, 146, 234, 1); }
.cm-s-material .cm-operator { color: rgba(233, 237, 237, 1); }
.cm-s-material .cm-variable-2 { color: #80CBC4; }
.cm-s-material .cm-variable-3 { color: #82B1FF; }
.cm-s-material .cm-builtin { color: #DECB6B; }
.cm-s-material .cm-atom { color: #F77669; }
.cm-s-material .cm-number { color: #F77669; }
.cm-s-material .cm-def { color: rgba(233, 237, 237, 1); }
.cm-s-material .cm-string { color: #C3E88D; }
.cm-s-material .cm-string-2 { color: #80CBC4; }
.cm-s-material .cm-comment { color: #546E7A; }
.cm-s-material .cm-variable { color: #82B1FF; }
.cm-s-material .cm-tag { color: #80CBC4; }
.cm-s-material .cm-meta { color: #80CBC4; }
.cm-s-material .cm-attribute { color: #FFCB6B; }
.cm-s-material .cm-property { color: #80CBAE; }
.cm-s-material .cm-qualifier { color: #DECB6B; }
.cm-s-material .cm-variable-3 { color: #DECB6B; }
.cm-s-material .cm-tag { color: rgba(255, 83, 112, 1); }
.cm-s-material .cm-error {
color: rgba(255, 255, 255, 1.0);
background-color: #EC5F67;
}
.cm-s-material .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}

View File

@ -0,0 +1,36 @@
/* Based on Sublime Text's Monokai theme */
.cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; }
.cm-s-monokai div.CodeMirror-selected { background: #49483E; }
.cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line > span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); }
.cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); }
.cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; }
.cm-s-monokai .CodeMirror-guttermarker { color: white; }
.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; }
.cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; }
.cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }
.cm-s-monokai span.cm-comment { color: #75715e; }
.cm-s-monokai span.cm-atom { color: #ae81ff; }
.cm-s-monokai span.cm-number { color: #ae81ff; }
.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; }
.cm-s-monokai span.cm-keyword { color: #f92672; }
.cm-s-monokai span.cm-builtin { color: #66d9ef; }
.cm-s-monokai span.cm-string { color: #e6db74; }
.cm-s-monokai span.cm-variable { color: #f8f8f2; }
.cm-s-monokai span.cm-variable-2 { color: #9effff; }
.cm-s-monokai span.cm-variable-3 { color: #66d9ef; }
.cm-s-monokai span.cm-def { color: #fd971f; }
.cm-s-monokai span.cm-bracket { color: #f8f8f2; }
.cm-s-monokai span.cm-tag { color: #f92672; }
.cm-s-monokai span.cm-header { color: #ae81ff; }
.cm-s-monokai span.cm-link { color: #ae81ff; }
.cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; }
.cm-s-monokai .CodeMirror-activeline-background { background: #373831; }
.cm-s-monokai .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}

View File

@ -0,0 +1,192 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("wa", function(config) {
var indentUnit = config.indentUnit;
var keywords = {
"break":true, "case":true, "const":true, "continue":true,
"default":true, "defer":true, "else":true, "for":true,
"func":true, "if":true, "import":true,
"interface":true, "map":true, "range":true, "return":true,
"struct":true, "switch":true, "type":true, "global":true,
"bool":true, "byte":true, "complex64":true, "complex128":true,
"f32":true, "f64":true, "i32":true, "i64":true, "u8":true, "u16":true, "u32":true, "u64": true,
"float32":true, "float64":true, "int8":true, "int16":true, "int32":true,
"int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true,
"uint64":true, "int":true, "uint":true, "uintptr":true, "error": true,
"rune":true
};
var atoms = {
"true":true, "false":true, "iota":true, "nil":true, "append":true,
"cap":true, "close":true, "complex":true, "copy":true, "delete":true, "imag":true,
"len":true, "make":true, "new":true, "panic":true, "print":true,
"println":true, "real":true, "assert":true, "this": true
};
var isOperatorChar = /[+\-*&^%:=<>!|\/]/;
var curPunc;
function tokenBase(stream, state) {
var ch = stream.next();
if (ch == '"' || ch == "'" || ch == "`") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
}
if (/[\d\.]/.test(ch)) {
if (ch == ".") {
stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/);
} else if (ch == "0") {
stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/);
} else {
stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/);
}
return "number";
}
if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
curPunc = ch;
return null;
}
if (ch == "#") {
stream.skipToEnd();
return "comment";
}
if (ch == "/") {
if (stream.eat("*")) {
state.tokenize = tokenComment;
return tokenComment(stream, state);
}
if (stream.eat("/")) {
stream.skipToEnd();
return "comment";
}
}
if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
return "operator";
}
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
var cur = stream.current();
if (keywords.propertyIsEnumerable(cur)) {
if (cur == "case" || cur == "default") curPunc = "case";
return "keyword";
}
if (atoms.propertyIsEnumerable(cur)) return "atom";
return "variable";
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, next, end = false;
while ((next = stream.next()) != null) {
if (next == quote && !escaped) {end = true; break;}
escaped = !escaped && quote != "`" && next == "\\";
}
if (end || !(escaped || quote == "`"))
state.tokenize = tokenBase;
return "string";
};
}
function tokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
}
return "comment";
}
function Context(indented, column, type, align, prev) {
this.indented = indented;
this.column = column;
this.type = type;
this.align = align;
this.prev = prev;
}
function pushContext(state, col, type) {
return state.context = new Context(state.indented, col, type, null, state.context);
}
function popContext(state) {
if (!state.context.prev) return;
var t = state.context.type;
if (t == ")" || t == "]" || t == "}")
state.indented = state.context.indented;
return state.context = state.context.prev;
}
// Interface
return {
startState: function(basecolumn) {
return {
tokenize: null,
context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
indented: 0,
startOfLine: true
};
},
token: function(stream, state) {
var ctx = state.context;
if (stream.sol()) {
if (ctx.align == null) ctx.align = false;
state.indented = stream.indentation();
state.startOfLine = true;
if (ctx.type == "case") ctx.type = "}";
}
if (stream.eatSpace()) return null;
curPunc = null;
var style = (state.tokenize || tokenBase)(stream, state);
if (style == "comment") return style;
if (ctx.align == null) ctx.align = true;
if (curPunc == "{") pushContext(state, stream.column(), "}");
else if (curPunc == "[") pushContext(state, stream.column(), "]");
else if (curPunc == "(") pushContext(state, stream.column(), ")");
else if (curPunc == "case") ctx.type = "case";
else if (curPunc == "}" && ctx.type == "}") ctx = popContext(state);
else if (curPunc == ctx.type) popContext(state);
state.startOfLine = false;
return style;
},
indent: function(state, textAfter) {
if (state.tokenize != tokenBase && state.tokenize != null) return 0;
var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
if (ctx.type == "case" && /^(?:case|default)\b/.test(textAfter)) {
state.context.type = "}";
return ctx.indented;
}
var closing = firstChar == ctx.type;
if (ctx.align) return ctx.column + (closing ? 0 : 1);
else return ctx.indented + (closing ? 0 : indentUnit);
},
electricChars: "{}):",
closeBrackets: "()[]{}''\"\"``",
fold: "brace",
blockCommentStart: "/*",
blockCommentEnd: "*/",
lineComment: "//"
};
});
CodeMirror.defineMIME("text/x-wa", "wa");
});

View File

@ -0,0 +1,340 @@
/* BASICS */
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 300px;
color: black;
}
/* PADDING */
.CodeMirror-lines {
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre {
padding: 0 4px; /* Horizontal padding of content */
}
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
background-color: white; /* The little square between H and V scrollbars */
}
/* GUTTER */
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: #f7f7f7;
white-space: nowrap;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: #999;
white-space: nowrap;
}
.CodeMirror-guttermarker { color: black; }
.CodeMirror-guttermarker-subtle { color: #999; }
/* CURSOR */
.CodeMirror-cursor {
border-left: 1px solid black;
border-right: none;
width: 0;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.cm-fat-cursor .CodeMirror-cursor {
width: auto;
border: 0 !important;
background: #7e7;
}
.cm-fat-cursor div.CodeMirror-cursors {
z-index: 1;
}
.cm-animate-fat-cursor {
width: auto;
border: 0;
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
animation: blink 1.06s steps(1) infinite;
background-color: #7e7;
}
@-moz-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
@-webkit-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
@keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror-overwrite .CodeMirror-cursor {}
.cm-tab { display: inline-block; text-decoration: inherit; }
.CodeMirror-rulers {
position: absolute;
left: 0; right: 0; top: -50px; bottom: -20px;
overflow: hidden;
}
.CodeMirror-ruler {
border-left: 1px solid #ccc;
top: 0; bottom: 0;
position: absolute;
}
/* DEFAULT THEME */
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-strikethrough {text-decoration: line-through;}
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable,
.cm-s-default .cm-punctuation,
.cm-s-default .cm-property,
.cm-s-default .cm-operator {}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
.cm-s-default .cm-error {color: #f00;}
.cm-invalidchar {color: #f00;}
.CodeMirror-composing { border-bottom: 2px solid; }
/* Default styles for common addons */
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
.CodeMirror-activeline-background {background: #e8f2ff;}
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
.CodeMirror {
position: relative;
overflow: hidden;
background: white;
}
.CodeMirror-scroll {
overflow: scroll !important; /* Things will break if this is overridden */
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
}
.CodeMirror-sizer {
position: relative;
border-right: 30px solid transparent;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actual scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
}
.CodeMirror-gutter-filler {
left: 0; bottom: 0;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
min-height: 100%;
z-index: 3;
}
.CodeMirror-gutter {
white-space: normal;
height: 100%;
display: inline-block;
vertical-align: top;
margin-bottom: -30px;
}
.CodeMirror-gutter-wrapper {
position: absolute;
z-index: 4;
background: none !important;
border: none !important;
}
.CodeMirror-gutter-background {
position: absolute;
top: 0; bottom: 0;
z-index: 4;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
.CodeMirror-lines {
cursor: text;
min-height: 1px; /* prevents collapsing before first draw */
}
.CodeMirror pre {
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
-webkit-tap-highlight-color: transparent;
-webkit-font-variant-ligatures: contextual;
font-variant-ligatures: contextual;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
overflow: auto;
}
.CodeMirror-widget {}
.CodeMirror-rtl pre { direction: rtl; }
.CodeMirror-code {
outline: none;
}
/* Force content-box sizing for the elements where we expect it */
.CodeMirror-scroll,
.CodeMirror-sizer,
.CodeMirror-gutter,
.CodeMirror-gutters,
.CodeMirror-linenumber {
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.CodeMirror-measure {
position: absolute;
width: 100%;
height: 0;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-cursor {
position: absolute;
pointer-events: none;
}
.CodeMirror-measure pre { position: static; }
div.CodeMirror-cursors {
visibility: hidden;
position: relative;
z-index: 3;
}
div.CodeMirror-dragcursors {
visibility: visible;
}
.CodeMirror-focused div.CodeMirror-cursors {
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.CodeMirror-crosshair { cursor: crosshair; }
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
.cm-searching {
background: #ffa;
background: rgba(255, 255, 0, .4);
}
/* Used to force a border model for a node */
.cm-force-border { padding-right: .1px; }
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursors {
visibility: hidden;
}
}
/* See issue #2901 */
.cm-tab-wrap-hack:after { content: ''; }
/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
/**
* Adapted from jQuery Lined Textarea Plugin
* http://alan.blog-city.com/jquerylinedtextarea.htm
*
* Released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*/
(function($) {
$.fn.linedtextarea = function() {
/*
* Helper function to make sure the line numbers are always kept up to
* the current system
*/
var fillOutLines = function(linesDiv, h, lineNo) {
while (linesDiv.height() <= h) {
linesDiv.append("<div>" + lineNo + "</div>");
lineNo++;
}
return lineNo;
};
return this.each(function() {
var lineNo = 1;
var textarea = $(this);
/* Wrap the text area in the elements we need */
textarea.wrap("<div class='linedtextarea' style='height:100%; overflow:hidden'></div>");
textarea.width("97%");
textarea.parent().prepend("<div class='lines' style='width:3%'></div>");
var linesDiv = textarea.parent().find(".lines");
var scroll = function(tn) {
var domTextArea = $(this)[0];
var scrollTop = domTextArea.scrollTop;
var clientHeight = domTextArea.clientHeight;
linesDiv.css({
'margin-top' : (-scrollTop) + "px"
});
lineNo = fillOutLines(linesDiv, scrollTop + clientHeight,
lineNo);
};
/* React to the scroll event */
textarea.scroll(scroll);
$(window).resize(function() { textarea.scroll(); });
/* We call scroll once to add the line numbers */
textarea.scroll();
});
};
})(jQuery);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,656 @@
html {
height: 100%;
}
body {
color: #fff;
padding: 0;
margin: 0;
width: 100%;
height: 100%;
background: #222;
}
a {
color: #1CA8B2;
}
#wrap,
#about {
padding: 5px;
margin: 0;
position: absolute;
top: 50px;
bottom: 25%;
left: 0;
right: 0;
}
#wrap {
background-color: #263238;
}
#about {
display: none;
z-index: 100;
padding: 10px 40px;
font-size: 16px;
font-family: Helvetica, Arial, sans-serif;
overflow: auto;
}
#about p {
max-width: 520px;
}
#about ul {
max-width: 480px;
}
#about li {
margin-bottom: 1em;
}
#code, #output, pre, .lines {
font-family: 'Go', 'Inconsolata', monospace;
font-size: 11pt;
}
#code {
color: black;
background: inherit;
width: 100%;
height: 100%;
padding: 0; margin: 0;
border: none;
outline: none;
resize: none;
wrap: off;
float: right;
background-color: #222;
color: #fff;
}
#output {
position: absolute;
top: 75%;
bottom: 0;
left: 0;
right: 0;
padding: 8px;
}
#output .system, #output .loading {
color: #555;
}
#output .stderr, #output .error {
color: #900;
}
#output pre {
margin: 0;
}
#banner {
position: absolute;
left: 0;
right: 0;
top: 0;
height: 50px;
background-color: #222;
color: #efefef;
}
#head {
float: left;
padding: 15px 10px;
font-size: 20px;
font-family: Helvetica, Arial, sans-serif;
}
#controls {
float: left;
padding: 10px 15px;
min-width: 245px;
}
#run {
background-color: #1CA8B2;
color: #ddd;
}
#run:hover {
color: #fff;
}
#about {
background-color: #333;
}
#aboutControls {
float: right;
padding: 10px 15px;
}
input[type=button],
#importsBox {
height: 30px;
font-size: 16px;
font-family: Helvetica, Arial, sans-serif;
color: #fff;
position: static;
top: 1px;
}
input[type=button] {
background: #333;
border: 1px solid #222;
cursor: pointer;
color: #bbb;
border-radius: 4px;
}
input[type=button]:hover {
color: #fff;
border: 1px solid #eee;
}
#importsBox {
position: relative;
display: inline;
padding: 5px 0;
margin-right: 5px;
}
#importsBox input {
position: relative;
top: -2px;
left: 1px;
height: 10px;
width: 10px;
}
#shareURL {
width: 280px;
font-size: 12px;
border: 1px solid #333;
background: #555;
color: #eee;
height: 23px;
}
#embedLabel {
font-family: Helvetica, Arial, sans-serif;
}
.lines {
float: left;
overflow: hidden;
text-align: right;
}
.lines div {
padding-right: 5px;
color: #555;
}
.lines div:hover {
color: #aaa;
background-color: #222;
}
.lines div.lineerror {
background-color: #222;
color: #900;
}
.exit {
color: #555;
}
#wrap .CodeMirror {
height: 100%;
font-family: 'Go', 'Inconsolata', monospace;
font-size: 11pt;
}
/* BASICS */
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 300px;
color: black;
}
/* PADDING */
.CodeMirror-lines {
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre {
padding: 0 4px; /* Horizontal padding of content */
}
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
background-color: white; /* The little square between H and V scrollbars */
}
/* GUTTER */
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: #f7f7f7;
white-space: nowrap;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: #999;
white-space: nowrap;
}
.CodeMirror-guttermarker { color: black; }
.CodeMirror-guttermarker-subtle { color: #999; }
/* CURSOR */
.CodeMirror-cursor {
border-left: 1px solid black;
border-right: none;
width: 0;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.cm-fat-cursor .CodeMirror-cursor {
width: auto;
border: 0 !important;
background: #7e7;
}
.cm-fat-cursor div.CodeMirror-cursors {
z-index: 1;
}
.cm-animate-fat-cursor {
width: auto;
border: 0;
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
animation: blink 1.06s steps(1) infinite;
background-color: #7e7;
}
@-moz-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
@-webkit-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
@keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror-overwrite .CodeMirror-cursor {}
.cm-tab { display: inline-block; text-decoration: inherit; }
.CodeMirror-rulers {
position: absolute;
left: 0; right: 0; top: -50px; bottom: -20px;
overflow: hidden;
}
.CodeMirror-ruler {
border-left: 1px solid #ccc;
top: 0; bottom: 0;
position: absolute;
}
/* DEFAULT THEME */
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-strikethrough {text-decoration: line-through;}
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable,
.cm-s-default .cm-punctuation,
.cm-s-default .cm-property,
.cm-s-default .cm-operator {}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
.cm-s-default .cm-error {color: #f00;}
.cm-invalidchar {color: #f00;}
.CodeMirror-composing { border-bottom: 2px solid; }
/* Default styles for common addons */
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
.CodeMirror-activeline-background {background: #e8f2ff;}
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
.CodeMirror {
position: relative;
overflow: hidden;
background: white;
}
.CodeMirror-scroll {
overflow: scroll !important; /* Things will break if this is overridden */
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
}
.CodeMirror-sizer {
position: relative;
border-right: 30px solid transparent;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actual scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
}
.CodeMirror-gutter-filler {
left: 0; bottom: 0;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
min-height: 100%;
z-index: 3;
}
.CodeMirror-gutter {
white-space: normal;
height: 100%;
display: inline-block;
vertical-align: top;
margin-bottom: -30px;
}
.CodeMirror-gutter-wrapper {
position: absolute;
z-index: 4;
background: none !important;
border: none !important;
}
.CodeMirror-gutter-background {
position: absolute;
top: 0; bottom: 0;
z-index: 4;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
.CodeMirror-lines {
cursor: text;
min-height: 1px; /* prevents collapsing before first draw */
}
.CodeMirror pre {
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
-webkit-tap-highlight-color: transparent;
-webkit-font-variant-ligatures: contextual;
font-variant-ligatures: contextual;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
overflow: auto;
}
.CodeMirror-widget {}
.CodeMirror-rtl pre { direction: rtl; }
.CodeMirror-code {
outline: none;
}
/* Force content-box sizing for the elements where we expect it */
.CodeMirror-scroll,
.CodeMirror-sizer,
.CodeMirror-gutter,
.CodeMirror-gutters,
.CodeMirror-linenumber {
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.CodeMirror-measure {
position: absolute;
width: 100%;
height: 0;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-cursor {
position: absolute;
pointer-events: none;
}
.CodeMirror-measure pre { position: static; }
div.CodeMirror-cursors {
visibility: hidden;
position: relative;
z-index: 3;
}
div.CodeMirror-dragcursors {
visibility: visible;
}
.CodeMirror-focused div.CodeMirror-cursors {
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.CodeMirror-crosshair { cursor: crosshair; }
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
.cm-searching {
background: #ffa;
background: rgba(255, 255, 0, .4);
}
/* Used to force a border model for a node */
.cm-force-border { padding-right: .1px; }
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursors {
visibility: hidden;
}
}
/* See issue #2901 */
.cm-tab-wrap-hack:after { content: ''; }
/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; }
/*
Name: Base16 Default Light
Author: Chris Kempson (http://chriskempson.com)
CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
*/
.cm-s-base16-light.CodeMirror { background: #f5f5f5; color: #202020; }
.cm-s-base16-light div.CodeMirror-selected { background: #e0e0e0; }
.cm-s-base16-light .CodeMirror-line::selection, .cm-s-base16-light .CodeMirror-line > span::selection, .cm-s-base16-light .CodeMirror-line > span > span::selection { background: #e0e0e0; }
.cm-s-base16-light .CodeMirror-line::-moz-selection, .cm-s-base16-light .CodeMirror-line > span::-moz-selection, .cm-s-base16-light .CodeMirror-line > span > span::-moz-selection { background: #e0e0e0; }
.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 0px; }
.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; }
.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; }
.cm-s-base16-light .CodeMirror-linenumber { color: #b0b0b0; }
.cm-s-base16-light .CodeMirror-cursor { border-left: 1px solid #505050; }
.cm-s-base16-light span.cm-comment { color: #8f5536; }
.cm-s-base16-light span.cm-atom { color: #aa759f; }
.cm-s-base16-light span.cm-number { color: #aa759f; }
.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute { color: #90a959; }
.cm-s-base16-light span.cm-keyword { color: #ac4142; }
.cm-s-base16-light span.cm-string { color: #f4bf75; }
.cm-s-base16-light span.cm-variable { color: #90a959; }
.cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; }
.cm-s-base16-light span.cm-def { color: #d28445; }
.cm-s-base16-light span.cm-bracket { color: #202020; }
.cm-s-base16-light span.cm-tag { color: #ac4142; }
.cm-s-base16-light span.cm-link { color: #aa759f; }
.cm-s-base16-light span.cm-error { background: #ac4142; color: #505050; }
.cm-s-base16-light .CodeMirror-activeline-background { background: #DDDCDC; }
.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }
/*
Name: material
Author: Michael Kaminsky (http://github.com/mkaminsky11)
Original material color scheme by Mattia Astorino (https://github.com/equinusocio/material-theme)
*/
.cm-s-material.CodeMirror {
background-color: #263238;
color: rgba(233, 237, 237, 1);
}
.cm-s-material .CodeMirror-gutters {
background: #263238;
color: rgb(83,127,126);
border: none;
}
.cm-s-material .CodeMirror-guttermarker, .cm-s-material .CodeMirror-guttermarker-subtle, .cm-s-material .CodeMirror-linenumber { color: rgb(83,127,126); }
.cm-s-material .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }
.cm-s-material div.CodeMirror-selected { background: rgba(255, 255, 255, 0.15); }
.cm-s-material.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }
.cm-s-material .CodeMirror-line::selection, .cm-s-material .CodeMirror-line > span::selection, .cm-s-material .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }
.cm-s-material .CodeMirror-line::-moz-selection, .cm-s-material .CodeMirror-line > span::-moz-selection, .cm-s-material .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }
.cm-s-material .CodeMirror-activeline-background { background: rgba(0, 0, 0, 0); }
.cm-s-material .cm-keyword { color: rgba(199, 146, 234, 1); }
.cm-s-material .cm-operator { color: rgba(233, 237, 237, 1); }
.cm-s-material .cm-variable-2 { color: #80CBC4; }
.cm-s-material .cm-variable-3 { color: #82B1FF; }
.cm-s-material .cm-builtin { color: #DECB6B; }
.cm-s-material .cm-atom { color: #F77669; }
.cm-s-material .cm-number { color: #F77669; }
.cm-s-material .cm-def { color: rgba(233, 237, 237, 1); }
.cm-s-material .cm-string { color: #C3E88D; }
.cm-s-material .cm-string-2 { color: #80CBC4; }
.cm-s-material .cm-comment { color: #546E7A; }
.cm-s-material .cm-variable { color: #82B1FF; }
.cm-s-material .cm-tag { color: #80CBC4; }
.cm-s-material .cm-meta { color: #80CBC4; }
.cm-s-material .cm-attribute { color: #FFCB6B; }
.cm-s-material .cm-property { color: #80CBAE; }
.cm-s-material .cm-qualifier { color: #DECB6B; }
.cm-s-material .cm-variable-3 { color: #DECB6B; }
.cm-s-material .cm-tag { color: rgba(255, 83, 112, 1); }
.cm-s-material .cm-error {
color: rgba(255, 255, 255, 1.0);
background-color: #EC5F67;
}
.cm-s-material .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}
/* Based on Sublime Text's Monokai theme */
.cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; }
.cm-s-monokai div.CodeMirror-selected { background: #49483E; }
.cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line > span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); }
.cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); }
.cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; }
.cm-s-monokai .CodeMirror-guttermarker { color: white; }
.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; }
.cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; }
.cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }
.cm-s-monokai span.cm-comment { color: #75715e; }
.cm-s-monokai span.cm-atom { color: #ae81ff; }
.cm-s-monokai span.cm-number { color: #ae81ff; }
.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; }
.cm-s-monokai span.cm-keyword { color: #f92672; }
.cm-s-monokai span.cm-builtin { color: #66d9ef; }
.cm-s-monokai span.cm-string { color: #e6db74; }
.cm-s-monokai span.cm-variable { color: #f8f8f2; }
.cm-s-monokai span.cm-variable-2 { color: #9effff; }
.cm-s-monokai span.cm-variable-3 { color: #66d9ef; }
.cm-s-monokai span.cm-def { color: #fd971f; }
.cm-s-monokai span.cm-bracket { color: #f8f8f2; }
.cm-s-monokai span.cm-tag { color: #f92672; }
.cm-s-monokai span.cm-header { color: #ae81ff; }
.cm-s-monokai span.cm-link { color: #ae81ff; }
.cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; }
.cm-s-monokai .CodeMirror-activeline-background { background: #373831; }
.cm-s-monokai .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,310 @@
// Copyright 2023 The Wa Authors. All rights reserved.
function HTTPTransport() {
'use strict';
function playback(output, events) {
var timeout;
output({Kind: 'start'});
function next() {
if (!events || events.length === 0) {
output({Kind: 'end'});
return;
}
var e = events.shift();
if (e.Delay === 0) {
output({Kind: 'stdout', Body: e.Message});
next();
return;
}
timeout = setTimeout(function() {
output({Kind: 'stdout', Body: e.Message});
next();
}, e.Delay / 1000000);
}
next();
return {
Stop: function() {
clearTimeout(timeout);
}
}
}
function error(output, msg) {
output({Kind: 'start'});
output({Kind: 'stderr', Body: msg});
output({Kind: 'end'});
}
var seq = 0;
return {
Run: function(body, output, options) {
seq++;
var cur = seq;
var playing;
$.ajax(playgroundOptions.compileURL, {
type: 'POST',
data: {'version': 2, 'body': body},
dataType: 'json',
success: function(data) {
if (seq != cur) return;
if (!data) return;
if (playing != null) playing.Stop();
if (data.Errors) {
error(output, data.Errors);
return;
}
playing = playback(output, data.Events);
},
error: function() {
error(output, 'Error communicating with remote server.');
}
});
return {
Kill: function() {
if (playing != null) playing.Stop();
output({Kind: 'end', Body: 'killed'});
}
};
}
};
}
function SocketTransport() {
'use strict';
var id = 0;
var outputs = {};
var started = {};
var websocket = new WebSocket('ws://' + window.location.host + '/socket');
websocket.onclose = function() {
console.log('websocket connection closed');
}
websocket.onmessage = function(e) {
var m = JSON.parse(e.data);
var output = outputs[m.Id];
if (output === null)
return;
if (!started[m.Id]) {
output({Kind: 'start'});
started[m.Id] = true;
}
output({Kind: m.Kind, Body: m.Body});
}
function send(m) {
websocket.send(JSON.stringify(m));
}
return {
Run: function(body, output, options) {
var thisID = id+'';
id++;
outputs[thisID] = output;
send({Id: thisID, Kind: 'run', Body: body, Options: options});
return {
Kill: function() {
send({Id: thisID, Kind: 'kill'});
}
};
}
};
}
function PlaygroundOutput(el) {
'use strict';
return function(write) {
if (write.Kind == 'start') {
el.innerHTML = '';
return;
}
var cl = 'system';
if (write.Kind == 'stdout' || write.Kind == 'stderr')
cl = write.Kind;
var m = write.Body;
if (write.Kind == 'end')
m = '\nProgram exited' + (m?(': '+m):'.');
if (m.indexOf('IMAGE:') === 0) {
// TODO(adg): buffer all writes before creating image
var url = 'data:image/png;base64,' + m.substr(6);
var img = document.createElement('img');
img.src = url;
el.appendChild(img);
return;
}
// ^L clears the screen.
var s = m.split('\x0c');
if (s.length > 1) {
el.innerHTML = '';
m = s.pop();
}
m = m.replace(/&/g, '&amp;');
m = m.replace(/</g, '&lt;');
m = m.replace(/>/g, '&gt;');
var needScroll = (el.scrollTop + el.offsetHeight) == el.scrollHeight;
var span = document.createElement('span');
span.className = cl;
span.innerHTML = m;
el.appendChild(span);
$(el).fadeIn()
if (needScroll)
el.scrollTop = el.scrollHeight - el.offsetHeight;
}
}
var playgroundOptions = {}
var defaultOptions = {
'compileURL': '/-/play/compile',
'fmtURL': '/-/play/fmt',
};
function kclPlaygroundOptions(opts) {
playgroundOptions = $.extend(defaultOptions, playgroundOptions, opts);
}
kclPlaygroundOptions({});
(function() {
function lineHighlight(error) {
var regex = /prog.wa:([0-9]+)/g;
var r = regex.exec(error);
while (r) {
$(".lines div").eq(r[1]-1).addClass("lineerror");
r = regex.exec(error);
}
}
function highlightOutput(wrappedOutput) {
return function(write) {
if (write.Body) lineHighlight(write.Body);
wrappedOutput(write);
}
}
function lineClear() {
$(".lineerror").removeClass("lineerror");
}
// opts is an object with these keys
// codeEl - code editor element
// outputEl - program output element
// runEl - run button element
// fmtEl - fmt button element (optional)
// enableHistory - enable using HTML5 history API (optional)
// transport - playground transport to use (default is HTTPTransport)
function playground(opts) {
var opts = $.extend(opts, playgroundOptions);
var code = $(opts.codeEl);
var transport = opts['transport'] || new HTTPTransport();
var running;
console.log(code);
var editorProps = {
lineNumbers: true,
indentWithTabs: false,
mode: 'wa',
smartIndent: true,
tabSize: 4,
indentUnit: 4,
};
if (typeof opts['theme'] !== 'undefined') {
editorProps.theme = opts['theme'];
}
var editor = CodeMirror.fromTextArea(code[0], editorProps);
var outdiv = $(opts.outputEl).empty().hide();
var output = $('<pre/>').appendTo(outdiv);
function body() {
return editor.getValue();
}
function setBody(text) {
editor.setValue(text);
}
function origin(href) {
return (""+href).split("/").slice(0, 3).join("/");
}
var pushedEmpty = (window.location.pathname == "/");
function inputChanged() {
if (pushedEmpty) {
return;
}
pushedEmpty = true;
$(opts.shareURLEl).hide();
window.history.pushState(null, "", "/");
}
function popState(e) {
if (e === null) {
return;
}
if (e && e.state && e.state.code) {
setBody(e.state.code);
}
}
var rewriteHistory = false;
if (window.history && window.history.pushState && window.addEventListener && opts.enableHistory) {
rewriteHistory = true;
code[0].addEventListener('input', inputChanged);
window.addEventListener('popstate', popState);
}
function setError(error) {
if (running) running.Kill();
lineClear();
lineHighlight(error);
output.empty().addClass("error").text(error);
if (error === "") {
outdiv.hide();
} else {
outdiv.fadeIn();
}
}
function loading() {
lineClear();
if (running) running.Kill();
output.removeClass("error").fadeIn().text('Waiting for remote server...');
}
function run() {
$(opts.outputEl).fadeIn();
loading();
running = transport.Run(body(), highlightOutput(PlaygroundOutput(output[0])));
}
function fmt() {
loading();
var data = {"body": body()};
data["imports"] = "true";
$.ajax(playgroundOptions.fmtURL, {
data: data,
type: "POST",
dataType: "json",
success: function(data) {
if (data.Error) {
setError(data.Error);
} else {
setBody(data.Body);
setError("");
}
}
});
}
$(opts.runEl).click(run);
$(opts.fmtEl).click(fmt);
}
window.playground = playground;
})();

View File

@ -0,0 +1,189 @@
html {
height: 100%;
}
body {
color: #fff;
padding: 0;
margin: 0;
width: 100%;
height: 100%;
background: #222;
}
a {
color: #1CA8B2;
}
#wrap,
#about {
padding: 5px;
margin: 0;
position: absolute;
top: 50px;
bottom: 25%;
left: 0;
right: 0;
}
#wrap {
background-color: #263238;
}
#about {
display: none;
z-index: 100;
padding: 10px 40px;
font-size: 16px;
font-family: Helvetica, Arial, sans-serif;
overflow: auto;
}
#about p {
max-width: 520px;
}
#about ul {
max-width: 480px;
}
#about li {
margin-bottom: 1em;
}
#code, #output, pre, .lines {
font-family: 'Go', 'Inconsolata', monospace;
font-size: 11pt;
}
#code {
color: black;
background: inherit;
width: 100%;
height: 100%;
padding: 0; margin: 0;
border: none;
outline: none;
resize: none;
wrap: off;
float: right;
background-color: #222;
color: #fff;
}
#output {
position: absolute;
top: 75%;
bottom: 0;
left: 0;
right: 0;
padding: 8px;
}
#output .system, #output .loading {
color: #555;
}
#output .stderr, #output .error {
color: #900;
}
#output pre {
margin: 0;
}
#banner {
position: absolute;
left: 0;
right: 0;
top: 0;
height: 50px;
background-color: #222;
color: #efefef;
}
#head {
float: left;
padding: 15px 10px;
font-size: 20px;
font-family: Helvetica, Arial, sans-serif;
}
#controls {
float: left;
padding: 10px 15px;
min-width: 245px;
}
#run {
background-color: #1CA8B2;
color: #ddd;
}
#run:hover {
color: #fff;
}
#about {
background-color: #333;
}
#aboutControls {
float: right;
padding: 10px 15px;
}
input[type=button],
#importsBox {
height: 30px;
font-size: 16px;
font-family: Helvetica, Arial, sans-serif;
color: #fff;
position: static;
top: 1px;
}
input[type=button] {
background: #333;
border: 1px solid #222;
cursor: pointer;
color: #bbb;
border-radius: 4px;
}
input[type=button]:hover {
color: #fff;
border: 1px solid #eee;
}
#importsBox {
position: relative;
display: inline;
padding: 5px 0;
margin-right: 5px;
}
#importsBox input {
position: relative;
top: -2px;
left: 1px;
height: 10px;
width: 10px;
}
#shareURL {
width: 280px;
font-size: 12px;
border: 1px solid #333;
background: #555;
color: #eee;
height: 23px;
}
#embedLabel {
font-family: Helvetica, Arial, sans-serif;
}
.lines {
float: left;
overflow: hidden;
text-align: right;
}
.lines div {
padding-right: 5px;
color: #555;
}
.lines div:hover {
color: #aaa;
background-color: #222;
}
.lines div.lineerror {
background-color: #222;
color: #900;
}
.exit {
color: #555;
}
#wrap .CodeMirror {
height: 100%;
font-family: 'Go', 'Inconsolata', monospace;
font-size: 11pt;
}

View File

@ -0,0 +1,65 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appplay
import (
"fmt"
"os"
"os/exec"
"runtime"
"strings"
"time"
"wa-lang.org/wa/internal/3rdparty/cli"
)
var CmdPlay = &cli.Command{
Name: "play",
Usage: "start Wa playground",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "http",
Value: ":2023",
Usage: "set http address",
},
},
Action: func(c *cli.Context) error {
err := RunPlayground(c.String("http"))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}
func RunPlayground(addr string) error {
if strings.HasPrefix(addr, ":") {
addr = "localhost" + addr
}
fmt.Printf("listen at http://%s\n", addr)
go func() {
time.Sleep(time.Second * 2)
openBrowser(addr)
}()
s := NewWebServer()
return s.Run(addr)
}
func openBrowser(url string) error {
if !strings.HasPrefix(url, "http") {
url = "http://" + url
}
switch runtime.GOOS {
case "linux":
return exec.Command("xdg-open", url).Start()
case "windows":
return exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
case "darwin":
return exec.Command("open", url).Start()
default:
return fmt.Errorf("unsupported platform")
}
}

View File

@ -0,0 +1,69 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appplay
import (
"bytes"
"embed"
"fmt"
"io/fs"
"net/http"
"strings"
"time"
)
type WebServer struct {
fs fs.FS
}
//go:embed _static
var fs_static embed.FS
func getStaticFS() fs.FS {
if true {
// return fs_static
}
fs, err := fs.Sub(fs_static, "_static")
if err != nil {
panic(err)
}
return fs
}
func NewWebServer() *WebServer {
p := &WebServer{
fs: getStaticFS(),
}
return p
}
func (p *WebServer) Run(addr string) error {
startTime := time.Now()
return http.ListenAndServe(addr,
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Method, r.URL.Path)
switch {
case r.URL.Path == "/":
p.editHandler(w, r)
case r.URL.Path == "/-/play/compile":
p.runHandler(w, r)
case r.URL.Path == "/-/play/fmt":
p.fmtHandler(w, r)
case strings.HasPrefix(r.URL.Path, "/static/"):
relpath := strings.TrimPrefix(r.URL.Path, "/static/")
data, err := fs.ReadFile(p.fs, relpath)
if err != nil {
http.NotFound(w, r)
return
}
http.ServeContent(w, r, r.URL.Path, startTime, bytes.NewReader(data))
default:
p.editHandler(w, r)
}
}),
)
}

View File

@ -0,0 +1,38 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appplay
import (
_ "embed"
"html/template"
"net/http"
)
func (p *WebServer) editHandler(w http.ResponseWriter, r *http.Request) {
snip := &Snippet{Body: []byte(edit_helloPlayground)}
edit_Template.Execute(w, &editData{snip})
}
//go:embed _edit.tmpl.html
var edit_tmpl string
var edit_Template = template.Must(template.New("playground/index.html").Parse(edit_tmpl))
const edit_helloPlayground = `// 版权 @2019 凹语言 作者。保留所有权利。
import "fmt"
import "runtime"
global year: i32 = 2023
func main {
println("你好,凹语言!", runtime.WAOS)
println(add(40, 2), year)
fmt.Println("1+1 =", 1+1)
}
func add(a: i32, b: i32) => i32 {
return a+b
}
`

View File

@ -0,0 +1,50 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appplay
import (
"encoding/json"
"fmt"
"net/http"
"wa-lang.org/wa/api"
"wa-lang.org/wa/internal/wamime"
)
func (p *WebServer) fmtHandler(w http.ResponseWriter, r *http.Request) {
var (
in = []byte(r.FormValue("body"))
err error
)
resp, err := p.fmtCode(in)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(resp); err != nil {
http.Error(w, fmt.Sprintf("error encoding response: %v", err), http.StatusInternalServerError)
return
}
}
func (p *WebServer) fmtCode(code []byte) (*fmtResponse, error) {
filename := "prog.wa"
if wamime.GetCodeMime(filename, code) == "wz" {
filename = "prog.wz"
}
output, err := api.FormatCode(filename, string(code))
if err != nil {
resp := &fmtResponse{
Error: err.Error(),
}
return resp, nil
}
resp := &fmtResponse{
Body: string(output),
}
return resp, nil
}

View File

@ -0,0 +1,66 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appplay
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"wa-lang.org/wa/api"
"wa-lang.org/wa/internal/wamime"
)
func (p *WebServer) runHandler(w http.ResponseWriter, r *http.Request) {
var req Request
version := r.PostFormValue("version")
if version == "2" {
req.Body = r.PostFormValue("body")
} else {
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, fmt.Sprintf("error decoding request: %v", err), http.StatusBadRequest)
return
}
}
resp, err := p.compileAndRun(&req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(resp); err != nil {
http.Error(w, fmt.Sprintf("error encoding response: %v", err), http.StatusInternalServerError)
return
}
}
func (p *WebServer) compileAndRun(req *Request) (*Response, error) {
tmpDir, err := ioutil.TempDir("", "sandbox")
if err != nil {
return nil, fmt.Errorf("error creating temp directory: %v", err)
}
defer os.RemoveAll(tmpDir)
filename := "prog.wa"
if wamime.GetCodeMime(filename, []byte(req.Body)) == "wz" {
filename = "prog.wz"
}
result, err := api.RunCode(api.DefaultConfig(), filename, req.Body)
if err != nil {
resp := &Response{Errors: err.Error()}
return resp, nil
}
resp := &Response{
Events: []Event{
{
Message: string(result),
Kind: "stdout",
},
},
}
return resp, nil
}

View File

@ -0,0 +1,35 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appplay
import (
"time"
)
type Snippet struct {
Body []byte
}
type Request struct {
Body string
}
type Response struct {
Errors string
Events []Event
}
type Event struct {
Message string
Kind string // "stdout" or "stderr"
Delay time.Duration // time to wait before printing Message
}
type editData struct {
Snippet *Snippet
}
type fmtResponse struct {
Body string
Error string
}

View File

@ -0,0 +1,64 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package apprun
import (
"fmt"
"os"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app/appbase"
"wa-lang.org/wa/internal/app/appbuild"
"wa-lang.org/wa/internal/wazero"
)
var CmdRun = &cli.Command{
Name: "run",
Usage: "compile and run Wa program",
Flags: []cli.Flag{
appbase.MakeFlag_target(),
appbase.MakeFlag_tags(),
},
Action: CmdRunAction,
}
func CmdRunAction(c *cli.Context) error {
input := c.Args().First()
outfile := ""
if input == "" {
input, _ = os.Getwd()
}
var opt = appbase.BuildOptions(c)
wasmBytes, err := appbuild.BuildApp(opt, input, outfile)
if err != nil {
return err
}
var appArgs []string
if c.NArg() > 1 {
appArgs = c.Args().Slice()[1:]
}
stdout, stderr, err := wazero.RunWasm(opt.Config(), input, wasmBytes, appArgs...)
if err != nil {
if len(stdout) > 0 {
fmt.Fprint(os.Stdout, string(stdout))
}
if len(stderr) > 0 {
fmt.Fprint(os.Stderr, string(stderr))
}
if exitCode, ok := wazero.AsExitError(err); ok {
os.Exit(exitCode)
}
fmt.Println(err)
}
if len(stdout) > 0 {
fmt.Fprint(os.Stdout, string(stdout))
}
if len(stderr) > 0 {
fmt.Fprint(os.Stderr, string(stderr))
}
return nil
}

View File

@ -0,0 +1,61 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package appssa
import (
"fmt"
"os"
"sort"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app/appbase"
"wa-lang.org/wa/internal/loader"
"wa-lang.org/wa/internal/ssa"
)
var CmdSsa = &cli.Command{
Hidden: true,
Name: "ssa",
Usage: "print Wa ssa code",
Flags: []cli.Flag{
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 := SSARun(opt, c.Args().First())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
}
func SSARun(opt *appbase.Option, filename string) error {
cfg := opt.Config()
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
}

View File

@ -0,0 +1,340 @@
// 版权 @2023 凹语言 作者。保留所有权利。
package apptest
import (
"bytes"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"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"
"wa-lang.org/wa/internal/wazero"
"wa-lang.org/wa/waroot"
)
var CmdTest = &cli.Command{
Name: "test",
Usage: "test Wa packages",
Flags: []cli.Flag{
appbase.MakeFlag_target(),
appbase.MakeFlag_tags(),
&cli.StringFlag{
Name: "run",
Usage: "set run func file name pattern",
Value: "",
},
},
Action: func(c *cli.Context) error {
opt := appbase.BuildOptions(c)
var pkgpath = "."
var runPattern = c.String("run")
var appArgs []string
if c.Args().Len() > 0 {
pkgpath = c.Args().First()
}
if c.Args().Len() > 1 {
appArgs = c.Args().Slice()[1:]
}
RunTest(opt.Config(), pkgpath, runPattern, appArgs...)
return nil
},
}
func RunTest(cfg *config.Config, pkgpath, runPattern string, appArgs ...string) {
var pkgList = []string{pkgpath}
if pkgpath == "std" {
pkgList = waroot.GetStdPkgTestList()
}
for _, p := range pkgList {
runTest(cfg, p, runPattern, appArgs...)
}
}
func runTest(cfg *config.Config, pkgpath, runPattern string, appArgs ...string) {
cfg.UnitTest = true
prog, err := loader.LoadProgram(cfg, pkgpath)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
startTime := time.Now()
mainPkg := prog.Pkgs[prog.Manifest.MainPkg]
wasmName := "unittest://" + pkgpath
wasmArgs := []string{}
if len(mainPkg.TestInfo.Files) == 0 {
fmt.Printf("? %s [no test files]\n", prog.Manifest.MainPkg)
return
}
// 生成 wat 文件(main 函数为空)
watOutput, err := compiler_wat.New().Compile(prog, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// wat 落盘(仅用于调试)
os.WriteFile("a.out.wat", []byte(watOutput), 0666)
// 编译为 wasm
wasmBytes, err := wabt.Wat2Wasm([]byte(watOutput))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
m, err := wazero.BuildModule(cfg, wasmName, wasmBytes, wasmArgs...)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer m.Close()
// 执行测试函数
var firstError error
for i := 0; i < len(mainPkg.TestInfo.Tests); i++ {
t := mainPkg.TestInfo.Tests[i]
if runPattern != "" {
matched, err := filepath.Match(runPattern, t.Name)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if !matched {
continue
}
}
tFuncName := mainPkg.Pkg.Path() + "." + t.Name
tFuncName = strings.ReplaceAll(tFuncName, "/", "$")
_, stdout, stderr, err := m.RunFunc(tFuncName)
if t.OutputPanic {
stdout = fmtGotOutput(stdout)
expect, got := t.Output, string(stdout)
if exitCode, _ := wazero.AsExitError(err); exitCode == 0 {
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
fmt.Printf(" expect panic, got = nil\n")
if firstError == nil {
firstError = fmt.Errorf("expect(panic) = %q, got = %q", expect, "nil")
}
continue
}
if !strings.HasPrefix(got, "panic: "+expect) { // panic: ${expect} (pos)
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
fmt.Printf(" expect(panic) = %q, got = %q\n", expect, got)
if firstError == nil {
firstError = fmt.Errorf("expect(panic) = %q, got = %q", expect, got)
}
}
// 重新加载
{
m, err = wazero.BuildModule(cfg, wasmName, wasmBytes, wasmArgs...)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// 临时方案: defer 太多
defer m.Close()
}
continue
}
if err != nil {
if len(stdout) > 0 {
if s := sWithPrefix(string(stdout), " "); s != "" {
fmt.Println(s)
}
}
if len(stderr) > 0 {
if s := sWithPrefix(string(stderr), " "); s != "" {
fmt.Println(s)
}
} else {
if s := sWithPrefix(err.Error(), " "); s != "" {
fmt.Println(s)
}
}
os.Exit(1)
}
stdout = fmtGotOutput(stdout)
if t.Output != "" && t.Output == string(stdout) {
continue
}
if err != nil {
if firstError == nil {
firstError = err
}
if _, ok := wazero.AsExitError(err); ok {
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
if s := sWithPrefix(string(stdout), " "); s != "" {
fmt.Println(s)
}
if s := sWithPrefix(string(stderr), " "); s != "" {
fmt.Println(s)
}
} else {
fmt.Println(err)
}
}
if t.Output != "" {
if expect, got := t.Output, string(stdout); expect != got {
if firstError == nil {
firstError = fmt.Errorf("expect = %q, got = %q", expect, got)
}
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
fmt.Printf(" expect = %q, got = %q\n", expect, got)
}
}
}
for i := 0; i < len(mainPkg.TestInfo.Examples); i++ {
t := mainPkg.TestInfo.Examples[i]
if runPattern != "" {
matched, err := filepath.Match(runPattern, t.Name)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if !matched {
continue
}
}
tFuncName := mainPkg.Pkg.Path() + "." + t.Name
tFuncName = strings.ReplaceAll(tFuncName, "/", "$")
_, stdout, stderr, err := m.RunFunc(tFuncName)
if t.OutputPanic {
stdout = fmtGotOutput(stdout)
expect, got := t.Output, string(stdout)
if exitCode, _ := wazero.AsExitError(err); exitCode == 0 {
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
fmt.Printf(" expect panic, got = nil\n")
if firstError == nil {
firstError = fmt.Errorf("expect panic, got = nil")
}
continue
}
if !strings.HasPrefix(got, "panic: "+expect) { // panic: ${expect} (pos)
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
fmt.Printf(" expect(panic) = %q, got = %q\n", expect, got)
if firstError == nil {
firstError = fmt.Errorf("expect(panic) = %q, got = %q", expect, got)
}
}
// 重新加载
{
m, err = wazero.BuildModule(cfg, wasmName, wasmBytes, wasmArgs...)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// 临时方案: defer 太多
defer m.Close()
}
continue
}
if err != nil {
if len(stdout) > 0 {
if s := sWithPrefix(string(stdout), " "); s != "" {
fmt.Println(s)
}
}
if len(stderr) > 0 {
if s := sWithPrefix(string(stderr), " "); s != "" {
fmt.Println(s)
}
}
os.Exit(1)
}
stdout = fmtGotOutput(stdout)
if t.Output != "" && t.Output == string(stdout) {
continue
}
if err != nil {
if firstError == nil {
firstError = err
}
if _, ok := wazero.AsExitError(err); ok {
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
if s := sWithPrefix(string(stdout), " "); s != "" {
fmt.Println(s)
}
if s := sWithPrefix(string(stderr), " "); s != "" {
fmt.Println(s)
}
} else {
fmt.Println(err)
}
}
if t.Output != "" {
if expect, got := t.Output, string(stdout); expect != got {
if firstError == nil {
firstError = fmt.Errorf("expect = %q, got = %q", expect, got)
}
fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name)
fmt.Printf(" expect = %q, got = %q\n", expect, got)
}
}
}
if firstError != nil {
fmt.Printf("FAIL %s %v\n", prog.Manifest.MainPkg, time.Now().Sub(startTime).Round(time.Millisecond))
os.Exit(1)
}
fmt.Printf("ok %s %v\n", prog.Manifest.MainPkg, time.Now().Sub(startTime).Round(time.Millisecond))
return
}
func sWithPrefix(s, prefix string) string {
lines := strings.Split(strings.TrimSpace(s), "\n")
for i, line := range lines {
lines[i] = prefix + strings.TrimSpace(line)
}
return strings.Join(lines, "\n")
}
func fmtGotOutput(stdout []byte) []byte {
stdout = bytes.TrimSpace(stdout)
lines := bytes.Split(stdout, []byte("\n"))
for i, s := range lines {
lines[i] = bytes.TrimSpace(s)
}
return bytes.Join(lines, []byte("\n"))
}

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