增加 CSP-J 2025 的例子

This commit is contained in:
chai2010
2025-11-02 20:52:36 +08:00
parent f34df7f2eb
commit d503472cca
8 changed files with 171 additions and 3 deletions

View File

@@ -5,6 +5,7 @@ package wazero
import (
"context"
"fmt"
"io"
"os"
"wa-lang.org/wa/internal/3rdparty/wazero"
@@ -28,6 +29,64 @@ func (p *Module) JsInstantiate(ctx context.Context, rt wazero.Runtime) (api.Clos
WithParameterNames("pos").
Export("print_position").
// func get_stdin_size() i32
NewFunctionBuilder().
WithFunc(func(ctx context.Context, m api.Module) int32 {
if cap(p.stdinBuffer) == 0 {
sysCtx := walang.ModCallContextSys(m)
p.stdinBuffer, _ = io.ReadAll(sysCtx.Stdin())
}
if cap(p.stdinBuffer) == 0 {
p.stdinBuffer = p.stdinBuffer[:0:0]
}
return int32(len(p.stdinBuffer))
}).
WithParameterNames().
Export("get_stdin_size").
// func get_stdin_data(ptr i32)
NewFunctionBuilder().
WithFunc(func(ctx context.Context, m api.Module, ptr uint32) {
if cap(p.stdinBuffer) == 0 {
sysCtx := walang.ModCallContextSys(m)
p.stdinBuffer, _ = io.ReadAll(sysCtx.Stdin())
}
if cap(p.stdinBuffer) == 0 {
p.stdinBuffer = p.stdinBuffer[:0:0]
}
m.Memory().Write(ctx, ptr, p.stdinBuffer)
}).
WithParameterNames("ptr").
Export("get_stdin_data").
// func get_argument_count() i32
NewFunctionBuilder().
WithFunc(func(ctx context.Context, m api.Module) int32 {
return int32(len(p.wasmArgs))
}).
WithParameterNames().
Export("get_argument_count").
// func get_argument_length(index i32) i32
NewFunctionBuilder().
WithFunc(func(ctx context.Context, m api.Module, index uint32) int32 {
if i := int(index); i >= 0 && i < len(p.wasmArgs) {
return int32(len(p.wasmArgs[i]))
}
return 0
}).
WithParameterNames("index").
Export("get_argument_length").
// func get_argument_data(index i32, ptr i32)
NewFunctionBuilder().
WithFunc(func(ctx context.Context, m api.Module, index, ptr uint32) {
m.Memory().Write(ctx, ptr, []byte(p.wasmArgs[index]))
}).
WithParameterNames("index", "ptr").
Export("get_argument_data").
// func print_bool(v: bool)
NewFunctionBuilder().
WithFunc(func(ctx context.Context, m api.Module, v uint32) {

View File

@@ -10,7 +10,6 @@ import (
"os"
"runtime"
"strings"
"sync"
"wa-lang.org/wa/internal/3rdparty/wazero"
"wa-lang.org/wa/internal/3rdparty/wazero/api"
@@ -25,11 +24,12 @@ type Module struct {
fsetBytes []byte
wasmArgs []string
stdinBuffer []byte // cap(x) == 0
fset *token.FileSet
stdoutBuffer bytes.Buffer
stderrBuffer bytes.Buffer
wazeroOnce sync.Once
wazeroCtx context.Context
wazeroConf wazero.ModuleConfig
wazeroRuntime wazero.Runtime

View File

@@ -0,0 +1,10 @@
# 版权 @2025 凹语言 作者。保留所有权利。
wa:
go run ../../../main.go run number.wa < number.in
wz:
go run ../../../main.go run number.wz < number.in
clean:

View File

@@ -0,0 +1 @@
290es1q0

View File

@@ -0,0 +1,36 @@
// CSP 2025入门组第二轮 第1题
#wa:import syscall_js get_stdin_size
func get_stdin_size => i32
#wa:import syscall_js get_stdin_data
func get_stdin_data(ptr: i32)
#wa:linkname $wa.runtime.slice_to_ptr
func byte_slice_to_ptr(t: []byte) => i32
func main {
n := int(get_stdin_size())
d := make([]byte, n)
get_stdin_data(byte_slice_to_ptr(d))
solve(string(d))
}
func solve(s: string) {
digits := make([]int, 10)
// 统计数字的个数
for _, c := range s {
if c >= '0' && c <= '9' {
digits[c-'0']++
}
}
// 倒序输出
for i := 9; i >= 0; i-- {
for k := 0; k < digits[i]; k++ {
print(string('0' + i))
}
}
}

View File

@@ -0,0 +1,35 @@
注: CSP 2025入门组第二轮 第1题
#凹:引入 syscall_js get_stdin_size
函数·获取标准输入数据大小 => 普整型
#凹:引入 syscall_js get_stdin_data
函数·获取标准输入数据(指针: 普整型)
#凹:链接名 $wa.runtime.slice_to_ptr
函数·字节切片地址(a: []字节) => 普整型
函数·主控:
输入 := 构建([]字节, 整型(获取标准输入数据大小()))
获取标准输入数据(字节切片地址(输入))
解题(字串(输入))
完毕
函数·解题(输入: 字串):
数字表 := 构建([]整型, 10)
注: 统计数字的个数
循环 _, 某 := 迭代 输入:
如果 某 >= '0' && 某 <= '9':
数字表[某-'0']++
完毕
完毕
注: 倒序输出
循环 甲 := 9; 甲 >= 0; 甲--:
循环 乙 := 0; 乙 < 数字表[甲]; 乙++:
打印(字串('0' + 甲))
完毕
完毕
完毕

View File

@@ -0,0 +1,27 @@
# CSP-J 环境说明
因为涉及读写stdin或命令行参数需要依赖以下的宿主函数
```
#wa:import syscall_js get_stdin_size
func get_stdin_size => i32
#wa:import syscall_js get_stdin_data
func get_stdin_data(ptr: i32)
#wa:linkname $wa.runtime.slice_to_ptr
func byte_slice_to_ptr(t: []byte) => i32
```
在内置的`syscall_js`环境已经包含了以上的函数。如果是自定义的wasm环境需要手动配置。
Windows系统标准输入有两种方式
- `echo 290es1q0 | prog.exe` 将 "290es1q0" 字符串作为 stdin 数据
- `prog.exe < number.in` 将 number.in 文件内容作为 stdin 数据
如果没有指定标准输入,同时程序里有执行了从 stdin 读取的操作,可能会发生阻塞。可以通过输入按 Ctrl + ZLinux下按 Ctrl + D然后按 Enter 方式模拟 stdin 文件结束。
## BUG
中文版底层尚有问题,正在修复中。

View File

@@ -1,4 +1,4 @@
// 版权 @2025 凹语言-小画家 作者。保留所有权利。
注: 版权 @2025 凹语言-小画家 作者。保留所有权利。
引入 "小画家"