Skip to content

Commit

Permalink
Merge pull request #72 from niuez/v0.7
Browse files Browse the repository at this point in the history
v0.7
  • Loading branch information
niuez authored Oct 13, 2021
2 parents f5373b0 + 94b1b9c commit d190a7a
Show file tree
Hide file tree
Showing 34 changed files with 1,012 additions and 55 deletions.
9 changes: 7 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-latest, macos-latest]

runs-on: ${{ matrix.os }}
defaults:
Expand All @@ -27,5 +27,10 @@ jobs:
- name: Run tests for library
run: |
for file in `find lib -name **.niu`; do
echo $file && NIU_IMPORT_PATH="./lib/;" cargo run $file >| 1.cpp && g++ -std=c++17 1.cpp -c
echo $file && NIU_IMPORT_PATH="./lib/;" cargo run trans $file >| 1.cpp && g++ -std=c++17 1.cpp -c
done
- name: Run unit tests
run: |
pip3 install toml Markdown colorlog jinja2
RUST_LOG=info NIU_IMPORT_PATH="./;" cargo run test
working-directory: ./lib
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ edition = "2018"
nom = "6.0.0"
log = "0.4.0"
env_logger = "0.8.4"
clap = "2.33.3"
toml = "0.5.8"
serde = { version = "^1.0.130", features = ["derive"] }
50 changes: 50 additions & 0 deletions doc/test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# ユニットテスト

Niu言語のユニットテストでは, [library-checker-problems](https://github.com/yosupo06/library-checker-problems)で使われている問題を使うことができます.

## library.toml

`library.toml`にテストをするための設定を書いておきます. 以下は一例です.

```toml
compiler="g++"
compile_options=["-std=c++17"]

[[testers]]
name="library-checker-problems"
repo="https://github.com/yosupo06/library-checker-problems"
generator="generate.py"
```

- `compiler`: コンパイラの指定
- `compile_options`: コンパイラに渡すオプション
- testers
- `name`: テストに使う問題集の名前
- `repo`: 問題があるリポジトリのurl
- `generator`: 入出力を生成するために使うスクリプトの指定

## ユニットテストの書きかた

`aplusb`を例に書いてみます.

```
import "std/u64.niu"
fn aplusb(a: u64, b: u64) -> u64 {
a + b
}
testfn(library-checker-problems:sample/aplusb) aplusb_test $${
long long a, b;
std::cin >> a >> b;
std::cout << aplusb(a, b) << "\n";
}$$
```

`testfn([テストの名前(name)]:[問題のディレクトリ]) [テスト名] $${ [C++のコード] }$$` C++のコードの内容が`int main()`に展開され, テストされます.

## テストの実行

`niu test`

`transpile/`にトランスパイルしたコードが出力され, `.test/`にテストに必要なコードが出力されます.
4 changes: 4 additions & 0 deletions examples/double_reference.niu
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main() -> void {
let a = 5;
let b = &&a;
}
22 changes: 22 additions & 0 deletions examples/eq.niu
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import "std/opes.niu"

impl Eq for u64 {
fn eq(self: &Self, right: &Self) -> bool $${self == right}$$
}

struct Hoge<T> {
v: T,
} {}

impl<T> Eq for Hoge<T> where T: Eq {
fn eq(self: &Self, right: &Self) -> bool {
self.v == right.v
}
}

fn main() -> void {
let a = Hoge { v: 3 };
let b = Hoge { v: 4 };
let ans = a == b;
let ans2 = a != b;
}
29 changes: 29 additions & 0 deletions examples/ord.niu
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import "std/opes.niu"
import "std/u64.niu"
import "std/vec.niu"

struct Hoge<T> {
v: T,
} {}

impl<T> Eq for Hoge<T> where T: Eq {
fn eq(a: &Self, b: &Self) -> bool {
a.v == b.v
}
}

impl<T> Ord for Hoge<T> where T: Ord {
fn le(a: &Self, b: &Self) -> bool {
a.v < b.v
}
}

fn main() -> void {
let a = Hoge { v: 3 };
let b = Hoge { v: 2 };
let ans = a < b;
let mut vec = Vec::new();
vec.push(a);
vec.push(b);
vec.sort();
}
7 changes: 1 addition & 6 deletions lib/data_structure/segment_tree.niu
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,13 @@ trait Monoid {
fn ope(self: &Self, right: &Self) -> Self;
}

impl Monoid for i64 {
fn ide() -> i64 { 0i64 }
fn ope(self: &i64, right: &i64) -> i64 { *self + *right }
}

struct SegmentTree<T> where T: Monoid {
node: Vec<T>,
n: u64,
} {
fn init(arr: &Vec<T>) -> Self {
let mut n = 1;
for n = 1; n < arr.len(); n = n * 2 {}
for i = 1; n < arr.len(); n = n * 2 {}
let mut node = Vec::init(2 * n, T#Monoid::ide());
for i = 0; i < arr.len(); i = i + 1 {
node[i + n] = arr[i];
Expand Down
85 changes: 85 additions & 0 deletions lib/data_structure/segment_tree_test.niu
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import "segment_tree.niu"
import "math/modint.niu"

struct Am {
v: i64,
} {
fn init(v: i64) -> Am {
Am { v: v }
}
}

impl Monoid for Am {
fn ide() -> Am { Am::init(0i64) }
fn ope(self: &Am, right: &Am) -> Am {
Am::init(self.v + right.v)
}
}

struct Fm {
a: Modint<M9982>,
b: Modint<M9982>,
} {
fn init(a: u64, b: u64) -> Fm {
Fm { a: Modint::init(a), b: Modint::init(b) }
}
}

impl Monoid for Fm {
fn ide() -> Fm { Fm::init(1u64, 0u64) }
fn ope(a: &Fm, b: &Fm) -> Fm {
Fm { a: a.a * b.a, b: a.b * b.a + b.b }
}
}


testfn(library-checker-problems:datastructure/point_add_range_sum) segmenttree_point_add_range_sum $${
std::cin.tie(nullptr);
int N, Q;
std::cin >> N >> Q;
std::vector<Am> a(N, Am::init(0));
for(int i = 0; i < N; i++) {
long long v;
std::cin >> v;
a[i] = Am::init(v);
}
using Seg = SegmentTree<Am>;
auto seg = Seg::init(a);
while(Q--) {
int t, a, b;
std::cin >> t >> a >> b;
if(t == 0) {
Seg::update(seg, a, Am::init(Seg::get(seg, a).v + b));
}
else {
std::cout << Seg::sum(seg, a, b).v << '\n';
}
}
}$$

testfn(library-checker-problems:datastructure/point_set_range_composite) segmenttree_point_set_range_composite $${
std::cin.tie(nullptr);
int N, Q;
std::cin >> N >> Q;
std::vector<Fm> a(N, Fm::init(1, 0));
for(int i = 0; i < N; i++) {
long long v, w;
std::cin >> v >> w;
a[i] = Fm::init(v, w);
}
using Seg = SegmentTree<Fm>;
auto seg = Seg::init(a);
while(Q--) {
int t, a, b, c;
std::cin >> t >> a >> b >> c;
if(t == 0) {
Seg::update(seg, a, Fm::init(b, c));
}
else {
Fm ans = Seg::sum(seg, a, b);
std::cout << (ans.a * Modint<M9982>(c) + ans.b).a << '\n';
}
}
}$$


19 changes: 18 additions & 1 deletion lib/data_structure/union_find.niu
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ struct UnionFind {
fn init(N: u64) -> Self {
let mut par = Vec::new();
let mut sz = Vec::new();
for(let mut i = 0; i < N; i = i + 1) {
for i = 0; i < N; i = i + 1 {
par.push(N);
sz.push(1);
}
Expand Down Expand Up @@ -47,3 +47,20 @@ struct UnionFind {
}
}
}

testfn(library-checker-problems:datastructure/unionfind) unionfind_test $${
std::cin.tie(nullptr);
int N, Q;
std::cin >> N >> Q;
UnionFind uf = UnionFind::init(N);
while(Q--) {
int t, a, b;
std::cin >> t >> a >> b;
if(t == 0) {
UnionFind::unite(uf, a, b);
}
else {
std::cout << (UnionFind::root(uf, a) == UnionFind::root(uf, b)) << "\n";
}
}
}$$
7 changes: 7 additions & 0 deletions lib/library.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
compiler="g++"
compile_options=["-std=c++17", "-O2"]

[[testers]]
name="library-checker-problems"
repo="https://github.com/yosupo06/library-checker-problems"
generator="generate.py"
6 changes: 6 additions & 0 deletions lib/std/f64.niu
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,9 @@ impl Div<f64> for f64 {
type Output = f64;
fn div(a: Self, b: f64) -> f64 $${a / b}$$
}
impl Eq for f64 {
fn eq(a: &f64, b: &f64) -> bool $${a == b}$$
}
impl Ord for f64 {
fn le(a: &f64, b: &f64) -> bool $${a < b}$$
}
6 changes: 6 additions & 0 deletions lib/std/i64.niu
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,9 @@ impl Neg for i64 {
type Output = i64;
fn neg(a: Self) -> i64 $${-a}$$
}
impl Eq for i64 {
fn eq(a: &i64, b: &i64) -> bool $${a == b}$$
}
impl Ord for i64 {
fn le(a: &i64, b: &i64) -> bool $${a < b}$$
}
8 changes: 8 additions & 0 deletions lib/std/opes.niu
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,11 @@ trait Index {
trait IndexMut where Self: Index {
fn index_mut(self: &mut Self, i: Self#Index::Arg) -> &mut Self#Index::Output;
}

trait Eq {
fn eq(self: &Self, right: &Self) -> bool;
}

trait Ord where Self: Eq {
fn le(self: &Self, right: &Self) -> bool;
}
6 changes: 6 additions & 0 deletions lib/std/u64.niu
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,9 @@ impl Rem<u64> for u64 {
type Output = u64;
fn rem(a: Self, b: u64) -> u64 $${a % b}$$
}
impl Eq for u64 {
fn eq(a: &u64, b: &u64) -> bool $${a == b}$$
}
impl Ord for u64 {
fn le(a: &u64, b: &u64) -> bool $${a < b}$$
}
16 changes: 11 additions & 5 deletions lib/std/vec.niu
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
#include <vector>
#include <algorithm>
import "std/opes.niu"

struct Vec<T> $${std::vector<$ty(T)>}$$ {
fn new() -> Self $${std::vector<$ty(T)>()}$$
fn init(N: u64, t: T) -> Self $${std::vector<$ty(T)>($arg(N), $arg(t))}$$
fn push(self: &mut Self, t: T) -> void $${$arg(self)->push_back($arg(t))}$$
fn len(self: &Self) -> u64 $${$arg(self)->size()}$$
fn pop(self: &mut Self) -> void $${$arg(self)->pop_back()}$$
fn push(self: &mut Self, t: T) -> void $${$arg(self).push_back($arg(t))}$$
fn len(self: &Self) -> u64 $${$arg(self).size()}$$
fn pop(self: &mut Self) -> void $${$arg(self).pop_back()}$$
fn sort(self: &mut Self) -> void where T: Ord $${std::sort($arg(self).begin(), $arg(self).end())}$$
}

impl<T> Index for Vec<T> {
type Output = T;
type Arg = u64;
fn index(self: &Self, i: u64) -> &T $${(&$arg(self)->at($arg(i)))}$$
fn index(self: &Self, i: u64) -> &T $${$arg(self).at($arg(i))}$$
}

impl<T> IndexMut for Vec<T> {
fn index_mut(self: &mut Self, i: u64) -> &mut T $${(&$arg(self)->at($arg(i)))}$$
fn index_mut(self: &mut Self, i: u64) -> &mut T $${$arg(self).at($arg(i))}$$
}

impl<T> Eq for Vec<T> where T: Eq {
fn eq(self: &Self, right: &Self) -> bool $${self==right}$$
}
22 changes: 20 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,30 @@ Niu言語は, 競技プログラミングにおけるライブラリ制作のた

が目標です.

## 遊び方
## インストール

```sh
git clone https://github.com/niuez/Niu
cd Niu
cargo install --path .
niu help
```
cargo run test.niu

## トランスパイル

```sh
niu trans main.niu
# ライブラリのインポート先のディレクトリを指定
NIU_IMPORT_PATH="path/to/library;path/to/another/library/;" niu trans main.niu
```

環境変数`NIU_IMPORT_PATH`でインポートするライブラリのディレクトリを設定できます. このリポジトリの`lib/`を指定すると良いです.

## ユニットテスト

[library-checker-problems](https://github.com/yosupo06/library-checker-problems)を利用してユニットテストができます. [ユニットテスト](./doc/test.md)を参考にしてください.


## 言語仕様

- [基本的な部分(Rustとほぼ同じ)](./doc/base.md)
Expand Down
Loading

0 comments on commit d190a7a

Please sign in to comment.