Skip to content

Commit

Permalink
add doc and remove useless readme now
Browse files Browse the repository at this point in the history
  • Loading branch information
chloro-pn committed Jun 15, 2024
1 parent 597c502 commit 3a5d40a
Show file tree
Hide file tree
Showing 11 changed files with 66 additions and 186 deletions.
191 changes: 5 additions & 186 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,191 +2,10 @@

![](https://tokei.rs/b1/github/chloro-pn/wamon) ![](https://tokei.rs/b1/github/chloro-pn/wamon?category=files) ![Static Badge](https://img.shields.io/badge/c%2B%2B-20-blue)

一个c++实现的脚本语言,以c++为宿主环境运行。
Embedded Scripting Language Designed for C++

## design
## doc
see doc/*.md

* wamon的首要目标是提供与c++丝滑的交互能力,所见即所得、便于调试、类型安全、低阅读门槛、跨平台等特性的优先级均高于追求性能,因此本项目不会使用过多编译优化技术。

* wamon的变量是值语义的,变量的生命周期与作用域规则与c++保持一致,wamon不包含gc。

* wamon是两阶段的:脚本文本通过词法分析与语法分析后,需要进行语义分析,最后才能执行。

* wamon是强类型的,不支持c++中的隐式类型转换。

* wamon的使用一般遵循以下格式:

```c++
// wamon::Scanner负责词法分析,输入脚本文本,输出tokens
wamon::Scanner scan;
wamon::PackageUnit pu;
wamon::PackageUnit pu2;
auto tokens = scan.Scan(str);
// wamon::Parse函数负责语法分析,输入tokens,输出PackageUnit,每次只能Parse一个Package
pu = wamon::Parse(tokens);

tokens = scan.Scan(math_str);
pn2 = wamon::Parse(tokens);
// wamon::MergePackageUnits负责将多个Package合并为一个Package,其中涉及重命名和符号定位等工作,即使是一个包也需要进行这一步。
pu = wamon::MergePackageUnits(std::move(pu), std::move(pu2));

// wamon::TypeChecker负责语义分析,其中包括类型分析与上下文相关的语句和表达式的合法性分析等等,这个名字之后需要改,有歧义。
wamon::TypeChecker tc(pu);
std::string reason;
bool succ = tc.CheckAll(reason);
EXPECT_EQ(succ, true) << reason;
// 通过语义分析后,构造wamon::Interpreter,通过wamon::Interpreter提供的接口执行脚本
wamon::Interpreter ip(pu);
```
## 类型系统
##### wamon的类型系统如下:
- 基本类型:
- 内置类型
- int
- string
- byte
- double
- bool
- void
- 结构体类型
- 复合类型(类型加工器):
- 指针类型 * `ptr(int)`
- 列表类型 [num] `list(int)`
- 函数类型 <- `f((int, string) -> int)`
wamon为这些类型提供了以下内置方法(目前这里还没做多少,需要提供更多的方法):
* string:len() -> int
* string:at() -> byte
* string:append(byte|string) -> void
* list(T):at(int) -> T
* list(T):size() -> int
* list(T):insert(int, T) -> void
* list(T):push_back(T) -> void
* list(T):pop_back() -> void
* list(T):resize(int) -> void
* list(T):erase(int) -> void
* list(T):clear() -> void
* list(T):empty() -> bool
##### 类型转换
wamon是强类型的,通过双元运算符as进行类型转换工作,目前支持:
* int -> double
* double -> int
* int -> bool
* list(byte) -> string
* struct / struct trait -> struct trait
## struct、struct trait
wamon通过支持`struct`来支持ADT,struct声明的语法如下:
```c++
// 数据成员声明在struct块中
struct struct_name {
type identifier;
type identifier;
...
}
// 方法声明在method块中
method struct_name {
// 可以使用self代指调用该方法的变量
func method_name(param_list) -> type {
...
}
...
// wamon支持调用运算符重载
operator() (param_list) -> type {
...
}
}
```
wamon通过支持`struct trait`来支持运行时多态,struct trait和struct的区别在于:struct trait的方法只有声明没有定义,它只定义了一些struct应该有的数据成员和方法。

如果某个`struct A`拥有某个`struct trait B`定义的全部数据成员和方法,那么就称A满足B这种trait。

`struct trait`属于wamon的类型系统,因此一个变量可以是`struct trait`类型,只是无法直接构造这个类型的变量,需要从其它类型的变量转换而来。

如果`struct A`满足`struct trait B`,那么可以用as运算符将其转换为B类型。


## 值型别、变量定义和new表达式
wamon有与c++相似的值型别的概念,不过是简化版本,wamon中的变量有两种值型别:左值和右值:
* move运算符可以将左值变量变成右值变量,与c++不同的是,wamon中的move是一个单元运算符。
* 变量定义表达式的格式:`let var_name : type = expr | (expr_list);`,let定义的变量是左值类型
* 也可以通过new表达式定义一个匿名的临时变量:`new type(expr_list)`,new定义的变量是右值类型

## register cpp functions
wamon提供了如下接口将cpp函数注册到wamon运行时中(不提供类型转换和匹配操作,需要用户自己实现),ct在语义分析阶段调用,用户应该在ct中检查传入的参数类型是否符合要求,如果不符合需要抛出异常。
ht在运行阶段调用。

```c++
std::string RegisterCppFunctions(const std::string& name, BuiltinFunctions::CheckType ct,
BuiltinFunctions::HandleType ht);
// ...
using HandleType = std::function<std::shared_ptr<Variable>(std::vector<std::shared_ptr<Variable>>&&)>;
using CheckType = std::function<std::unique_ptr<Type>(const std::vector<std::unique_ptr<Type>>& params_type)>;
```
你也可以通过下面这个接口注册类型确定的内置函数:
```c++
void Interpreter::RegisterCppFunctions(const std::string& name, std::unique_ptr<Type> func_type,
BuiltinFunctions::HandleType ht);
```
这种内置函数参与类型分析,可以被赋值给Callable对象,详情见example/register_cpp_function.cc


## 函数是一等公民

wamon中的函数可以被赋值给变量、可以作为参数和返回值传递,是wamon中的一等公民。

wamon通过Callable变量持有原始函数、lambda表达式、重载了()运算符类型的变量。

Callable变量是指具有函数类型的变量:

`let callable_obj : f((int) -> int) = (...); `

Callable变量可以像普通变量一样被复制、传递、作为参数和返回值。

Callable变量可以出现在函数调用表达式表达式中:

`call callable_obj:(4); `

## hello world
```c++
#include <iostream>
#include <string>

#include "wamon/interpreter.h"
#include "wamon/parser.h"
#include "wamon/scanner.h"
#include "wamon/type_checker.h"
#include "wamon/variable.h"

int main() {
std::string script = R"(
package main;

func hello() -> string {
return "hello world";
}
)";

wamon::Scanner scanner;
auto tokens = scanner.Scan(script);
wamon::PackageUnit package_unit = wamon::Parse(tokens);
package_unit = wamon::MergePackageUnits(std::move(package_unit));
wamon::TypeChecker type_checker(package_unit);

std::string reason;
bool succ = type_checker.CheckAll(reason);
if (succ == false) {
std::cerr << "type check error : " << reason << std::endl;
return -1;
}
wamon::Interpreter ip(package_unit);
auto ret = ip.CallFunctionByName("main$hello", {});
std::cout << wamon::AsStringVariable(ret)->GetValue() << std::endl;
return 0;
}
```
## TODO
Update the readme file after writing the doc
Empty file added doc/builtin_function.md
Empty file.
Empty file added doc/expr_and_stmt.md
Empty file.
Empty file added doc/identifier_and_keyword.md
Empty file.
Empty file added doc/interpreter.md
Empty file.
Empty file added doc/operator.md
Empty file.
61 changes: 61 additions & 0 deletions doc/package.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
### before
关于wamon中`identifier`的概念见 `doc/identifier_and_keyword.md`

### package
wamon使用包(`package`)的概念组织源码,任何源代码文件必须属于某个包,同时源码文件的第一行有效代码必须是包声明语句,通过该语句声明自己所在的包。
包声明语句:`package identifier;`
包声明语句之后是0个或多个包导入语句(包导入语句是可选的)。
包导入语句:`import identifier;`

接下来是一系列可以在包作用域中定义的实体,包括:
- 全局变量的定义
变量定义语句见 `doc/expr_and_stmt.md`
- 结构体的定义
结构体定义的语法如下:
```
struct struct_name[type: identifier] {
type field_name[type: identifier];
type field_name[type: identifier];
...
}
```
- 结构体方法的定义
结构体方法定义的语法如下:
```
method struct_name[type: identifier] {
func method_name[type: identifier](param_list) -> type
stmt_block
operator()(param_list) -> type
stmt_block
destructor()
stmt_block
}
```
`method`块中的三类方法均是可选的,其中:
* `stmt_block`的含义见 `doc/expr_and_stmt`
* `param_list`的定义是,以逗号分割的`type var_name[type: identifier]`序列。
- 全局函数的定义
全局函数定义的语法如下:
```
func (param_list) -> type
stmt_block
```
- enum的定义
enum定义的语法如下:
```
enum enum_name[type: identifier] {
enum_item[type: identifier];
enum_item[type: identifier];
...
}
```
enum字面量的语法如下:`enum enum_name : enum_item`,例如:`enum Color:Blue`

### 实体引用规则
当引用同一个包内的实体时可以省略包名称,当引用其他包内的实体时需要在实体前加上包名称和作用域运算符(\:\:),例如:
* `call sort::merge_sort:(param_list)` 调用sort包内的merge_sort函数
* `enum draw::Color:Red` 声明一个enum常量,enum的类型是包draw内的Color
* `let v : f((int, int) -> int) = math::add;` 定义一个函数类型的变量,变量的值是math包的add全局函数。

Empty file added doc/register_cpp_function.md
Empty file.
Empty file added doc/type.md
Empty file.
Empty file added doc/type_check.md
Empty file.
Empty file added doc/variable.md
Empty file.

0 comments on commit 3a5d40a

Please sign in to comment.