koicore 0.2.2

core KoiLang module
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
<div align="center">
  <img src="koicore_header.png" width="800" alt="koicore banner">
</div>

# koicore

KoiLang 语言核心模块,提供基础语言功能。

[![License](https://img.shields.io/github/license/Visecy/koicore.svg)](LICENSE)
[![Crates.io](https://img.shields.io/crates/v/koicore.svg)](https://crates.io/crates/koicore)
[![Documentation](https://docs.rs/koicore/badge.svg)](https://docs.rs/koicore)

[English]./README.md | **中文**

## 概述

KoiLang 是一种专为叙事内容设计的标记语言,特别适用于视觉小说、互动小说和对话驱动的应用程序。`koicore` crate 提供了处理 KoiLang 文件所需的基本解析和数据结构。

KoiLang 的核心理念是分离数据和指令。KoiLang 文件包含数据(命令和文本),而您的应用程序提供指令(如何处理这些命令)。这使得 KoiLang 文件易于人类阅读和编写,同时足够强大以处理复杂应用程序。

## 特性

- **流式解析器**:以恒定内存使用量处理任意大小的文件
- **多种输入源**:支持从字符串、文件或自定义输入源解析
- **编码支持**:通过 `DecodeBufReader` 处理各种文本编码(UTF-8、GBK 等)
- **全面的错误处理**:带有源位置和上下文的详细错误消息
- **可配置的解析**:可自定义的命令阈值和解析规则
- **类型安全的数据结构**:强类型的命令和参数表示
- **高性能**:基于 Rust 的性能和安全保证构建
- **跨语言 FFI**:C 兼容 API,支持与 C/C++ 和其他语言集成

## 安装

将此添加到您的 `Cargo.toml`:

```toml
[dependencies]
koicore = "0.2.2"
```

## 从源码构建

```bash
# 克隆仓库
git clone https://github.com/Visecy/koicore.git
cd koicore

# 构建项目
make build

# 运行测试
make test

# 运行FFI测试
make ffi-test
```

## 快速开始

```rust
use koicore::parser::{Parser, ParserConfig, StringInputSource};
# fn main() -> Result<(), Box<dyn std::error::Error>> {
// 创建输入源
let input = StringInputSource::new(r#"
#character Alice "Hello, world!"
This is regular text content.
#background Forest
"#);

// 配置解析器
let config = ParserConfig::default();

// 创建解析器
let mut parser = Parser::new(input, config);

// 处理命令
while let Some(command) = parser.next_command()? {
    println!("Command: {}", command.name());
    for param in command.params() {
        println!("  Parameter: {}", param);
    }
}

# Ok(())
# }
```


## KoiLang 语法

KoiLang 使用基于命令前缀的简单、可读语法。核心概念是分离命令(指令)和文本内容(数据)。

### 命令
命令以 `#` 开头,后跟命令名称和参数:
```text
#character Alice "Hello, world!"
#background Forest
#action walk direction(left) speed(5)
```

### 文本内容
常规文本内容(没有 `#` 前缀)被视为叙述文本:
```text
This is regular text content.
It can span multiple lines.
```

### 注释
包含多个 `#` 字符的行被视为注释:
```text
## This is an annotation
### This is also an annotation
```

### 参数类型
KoiLang 支持各种参数类型:

#### 基本参数
- **整数**:十进制、二进制(`0b101`)和十六进制(`0x6CF`- **浮点数**:标准表示法(`1.0`)、科学记数法(`2e-2`- **字符串**:带引号的字符串(`"Hello world"`- **字面量**:不带引号的标识符(`string``__name__`
```text
#arg_int    1 0b101 0x6CF
#arg_float  1. 2e-2 .114514
#arg_literal string __name__
#arg_string "A string"
```

#### 复合参数
- **命名参数**`name(value)`
- **列表**`name(item1, item2, item3)`
- **字典**`name(key1: value1, key2: value2)`

```text
#kwargs key(value)
#keyargs_list key(item0, item1)
#kwargs_dict key(x: 11, y: 45, z: 14)
```

#### 复杂示例
所有参数类型都可以组合:
```text
#draw Line 2 pos0(x: 0, y: 0) pos1(x: 16, y: 16) \
    thickness(2) color(255, 255, 255)
```

### 命令名称
命令名称可以是:
- 有效标识符:`character``background``action`
- 数字命令:`#114``#1919`(用于编号序列很有用)

### 完整语法
在 KoiLang 中,文件包含'命令'部分和'文本'部分:
- 命令部分以 `#` 开头,遵循 C 风格的预处理语句格式
- 文本部分是所有其他不以 `#` 开头的行

单个命令的格式:
```text
#command_name [param 1] [param 2] ...
```

每个命令可以有多个不同类型的参数,允许灵活且富有表现力的命令结构。

### 前缀阈值
`command_threshold` 参数决定了 KoiLang 如何根据 `#` 字符的数量来识别行类型:

- `#` 字符数量 `< threshold` → 文本内容
- `#` 字符数量 `= threshold` → 命令
- `#` 字符数量 `> threshold` → 注释

```text
#single_hash_command "这是一个命令"
##double_hash_command "当 threshold=2 时这是一个命令"
###triple_hash_command "当 threshold=3 时这是一个命令"

这里是常规文本内容。
```

#### 阈值示例

| 阈值 | `#text` | `##text` | `###text` | `####text` | 无前缀行 |
|------|---------|----------|-----------|------------|----------|
| 0 | 注释 | 注释 | 注释 | 注释 | 命令 |
| 1(默认) | 命令 | 注释 | 注释 | 注释 | 文本 |
| 2 | 文本 | 命令 | 注释 | 注释 | 文本 |
| 3 | 文本 | 文本 | 命令 | 注释 | 文本 |

当 `threshold=0` 时,没有 `#` 前缀的行被视为命令,所有带有 `#` 前缀的行被视为注释。

#### 使用场景

- **threshold=1**: 标准 KoiLang 语法(默认)
- **threshold=2**: 允许在单井号有特殊含义的语言中嵌入 KoiLang(单 `#` 前缀视为文本)
- **threshold=3**: 用于复杂脚本的严格命令解析
- **threshold=0**: 特殊情况下,所有非哈希行都是命令,哈希行是注释

## 核心组件

### 命令结构
`Command` 结构表示解析后的 KoiLang 命令:

```rust
use koicore::command::{Command, Parameter};

# fn main() {
// 创建简单命令
let cmd = Command::new("character", vec![
    Parameter::from("Alice"),
    Parameter::from("Hello, world!")
]);

// 创建文本和注释命令
let text_cmd = Command::new_text("Narrative text");
let annotation_cmd = Command::new_annotation("Annotation text");
# }
```

### 解析器配置
使用 `ParserConfig` 自定义解析行为:

```rust
use koicore::parser::ParserConfig;

# fn main() {
// 默认配置(阈值 = 1)
let config = ParserConfig::default();

// 自定义阈值 - 需要 2 个 # 字符作为命令
let config = ParserConfig::default().with_command_threshold(2);
# }
```

### 输入源
支持各种输入源:

```rust
use koicore::parser::{StringInputSource, FileInputSource};

# fn main() -> Result<(), Box<dyn std::error::Error>> {
// 从字符串解析
let input = StringInputSource::new("#test command");

// 从文件解析
let input = FileInputSource::new("script.ktxt")?;
# Ok(())
# }
```

### 文本生成 (Writer)
除了解析,`koicore` 还提供了灵活的写入器模块,用于以编程方式生成 KoiLang 代码:

```rust
use koicore::writer::{Writer, WriterConfig};
use koicore::command::{Command, Parameter};

# fn main() -> Result<(), Box<dyn std::error::Error>> {
// 配置写入器
let config = WriterConfig::default();
let mut buffer = Vec::new();
let mut writer = Writer::new(&mut buffer, config);

// 创建命令
let cmd = Command::new("character", vec![
    Parameter::from("Alice"),
    Parameter::from("Hello, world!")
]);

// 写入命令
writer.write_command(&cmd)?;

// 输出: #character Alice "Hello, world!"
println!("{}", String::from_utf8(buffer)?);
# Ok(())
# }
```

## 高级特性

### 理念:数据与指令的分离

KoiLang 的关键创新是关注点分离:
- **KoiLang 文件** 包含数据(命令和文本内容)
- **您的应用程序** 提供指令(如何处理这些命令)

这使得 KoiLang 文件易于人类阅读和编写,而您的应用程序可以实现复杂的逻辑来处理它们。可以将其视为一个简单的虚拟机引擎,其中 KoiLang 文件是字节码,而您的应用程序是 VM。

### 流式处理大文件
高效处理大文件:

```rust
use koicore::parser::{Parser, ParserConfig, FileInputSource};
use std::path::Path;

let input = FileInputSource::new(Path::new("large_script.ktxt"))?;
let config = ParserConfig::default();
let mut parser = Parser::new(input, config);

// 逐行处理,恒定内存使用量
while let Some(command) = parser.next_command()? {
    // 解析时处理每个命令
    process_command(command)?;
}
```

### 编码支持
支持 UTF-8 编码的内容:

```rust
use koicore::parser::{Parser, ParserConfig, StringInputSource};

# fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = StringInputSource::new(r#"
#title "Hello World"
#character Protagonist "Hello!"
"#);

let mut parser = Parser::new(input, ParserConfig::default());
while let Some(command) = parser.next_command()? {
    println!("Command: {}", command.name());
}
# Ok(())
# }
```

### 错误处理
带有上下文的全面错误报告:

```rust
use koicore::parser::{Parser, ParserConfig, StringInputSource};

let input = StringInputSource::new("#invalid command syntax");
let mut parser = Parser::new(input, ParserConfig::default());

match parser.next_command() {
    Ok(Some(command)) => println!("Parsed: {:?}", command),
    Ok(None) => println!("End of input"),
    Err(e) => {
        println!("Parse error: {}", e);
        println!("Error location: line {}", e.line_number());
    }
}
```

## 示例

### 文件生成示例

一个常见用例是使用 KoiLang 从单个源生成多个文件。以下是一个概念示例:

```text
#file "hello.txt" encoding("utf-8")
Hello world!
And there are all my friends.

#space hello
    #file "Bob.txt"
    Hello Bob.

    #file "Alice.txt"
    Hello Alice.
#endspace
```

这种模式允许您:
- 从单个 KoiLang 源创建多个文件
- 分层组织内容
- 保持一致的编码和格式

### 查看 `examples/` 目录获取更多详细示例:

- `decode_buf_reader_example.rs` - 演示编码支持和流式功能
- `ktxt/example0.ktxt` - 复杂叙事脚本示例
- `ktxt/example1.ktxt` - 简单文件结构示例

## 性能

解析器专为高性能设计:

- **流式处理**:无论文件大小,恒定内存使用量
- **零拷贝解析**:解析期间最小字符串分配
- **高效错误处理**:快速错误检测和报告
- **基准测试**`benches/` 目录中包含性能基准

运行基准测试:
```bash
cargo bench
```

## 与 Python Kola 的关系

koicore 与 Python Kola 之间的关系代表了 KoiLang 生态系统的演进:

1. **Kola** 是完整的第一代实现,提供解析器 + 写入器 + 上层封装。然而,它依赖于老旧的 flex 和 CPython API,使得 FFI 集成具有挑战性。

2. **koicore** 是新一代 KoiLang 内核,提供更高性能和跨语言的语言基础功能(解析器 + 写入器)。新的 KoiLang Python 绑定将构建在 koicore 之上。

3. **未来演进**:Kola 将逐步采用 koicore 作为底层实现,并将被新的绑定逐步取代。

这一过渡确保了 KoiLang 生态系统更好的性能、改进的跨语言兼容性和更易维护的代码库。

## 跨语言集成

对于使用 C、C++ 或其他编程语言编写的应用程序,koicore 提供了全面的外部函数接口(FFI)。FFI 模块(`koicore_ffi`)通过 C 兼容 API 公开所有核心 koicore 功能。

### 主要 FFI 特性

- **C 兼容 API**:完整的 C API,支持 C++ 命名空间包装
- **内存管理**:明确的所有权和安全的内存管理
- **完整覆盖**:访问所有解析器和命令功能
- **错误处理**:详细的错误报告,包含源位置信息
- **多种输入源**:支持字符串、文件和自定义输入回调
- **复合参数**:完整支持列表和字典

### 使用 FFI

详细的 FFI 文档可在 [`crates/koicore_ffi/README.md`](./crates/koicore_ffi/README.md) 中找到。包括:

- **构建和链接**:完整的构建说明和链接示例
- **API 参考**:完整的 C API 文档和示例
- **快速开始指南**:C/C++ 中的基本解析示例
- **高级用法**:自定义输入源、复合参数和错误处理
- **内存管理**:安全内存使用指南
- **线程安全**:并发使用的最佳实践

### 快速 FFI 示例

```c
#include "koicore.h"
#include <stdio.h>

int main() {
    // 从字符串创建输入源
    KoiInputSource* source = KoiInputSource_FromString("#character Alice \"Hello!\"");
    
    // 初始化解析器配置
    KoiParserConfig config;
    KoiParserConfig_Init(&config);
    
    // 创建解析器并解析命令
    KoiParser* parser = KoiParser_New(source, &config);
    KoiCommand* cmd = KoiParser_NextCommand(parser);
    
    if (cmd) {
        char name[256];
        KoiCommand_GetName(cmd, name, sizeof(name));
        printf("Command: %s\n", name);
        KoiCommand_Del(cmd);
    }
    
    KoiParser_Del(parser);
    return 0;
}
```

有关全面的使用示例和 API 详细信息,请参阅 [FFI 文档](./crates/koicore_ffi/README.md)。

## 许可证

本项目采用 MIT 许可证 - 有关详细信息,请参阅 [LICENSE](LICENSE) 文件。

## 贡献

欢迎贡献!请随时提交拉取请求。对于重大更改,请先打开一个问题来讨论您想要更改的内容。

## 仓库

[https://github.com/Visecy/koicore](https://github.com/Visecy/koicore)