Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
__pycache__/
*.py[cod]
*.egg-info/
.pytest_cache/

# .NET build output (golden_arraypool demo)
bin/
obj/
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ C# (шаблоны emit_* → реальный .NET; try/finally на straight-
### Запуск

```bash
cd ownlang
# запускать из корня репозитория (там, где лежит пакет ownlang/ и examples/)
python -m ownlang check examples/ok_extern_calls.own # проверка
python -m ownlang emit examples/golden_arraypool/buffer.own # проверка + печать C#
python -m ownlang cfg examples/bad_maybe_release.own # дамп CFG
Expand All @@ -60,7 +60,10 @@ python tests/run_tests.py # 42 кейса + c

```bash
cd examples/golden_arraypool
dotnet run # требует .NET SDK; в песочнице PoC его нет
# Здесь лежат buffer.own (источник) и Program.cs (сгенерённый process + host).
# Своего .csproj PoC не возит; чтобы запустить — заверни Program.cs в console-проект:
dotnet new console -o demo && cp Program.cs demo/ && cd demo && dotnet run
# (требует .NET SDK; в песочнице PoC его нет — проверено по построению, не запуском)
```

`buffer.own` объявляет ресурс `Buffer` с шаблонами `emit_*`, отображающими его на
Expand Down Expand Up @@ -208,7 +211,7 @@ fn process(size: int) {
| **OWN004** | borrow убегает из своей области (например, `return` borrow'а) |
| **OWN005** | use/… после move (**definite**) |
| **OWN006** | `borrow_mut` при живом shared borrow |
| **OWN007** | move/consume владельца под живым borrow'ом |
| **OWN007** | move/consume/return владельца под живым borrow'ом |
| **OWN008** | release владельца под живым borrow'ом |
| **OWN009** | операция над ресурсом, который **мог** быть освобождён на каком-то пути (**maybe**) |
| **OWN010** | операция над ресурсом, который **мог** быть перемещён на каком-то пути (**maybe**) |
Expand Down Expand Up @@ -389,6 +392,6 @@ ownlang/
examples/
ok_*.own # проходят
bad_*.own # падают с конкретным кодом
golden_arraypool/ # buffer.own + Program.cs + demo.csproj (dotnet run)
golden_arraypool/ # buffer.own + Program.cs (host-код; .csproj не входит)
tests/run_tests.py # 42 кейса анализа + codegen smoke + golden smoke
```
File renamed without changes.
18 changes: 18 additions & 0 deletions examples/bad_maybe_release.own
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module MaybeReleaseDemo

resource Buffer {
acquire rent
release give
}

// 'b' is released on the 'then' path only. At the join its state is
// inconsistent, so the following `use b` touches a maybe-released value
// (OWN009). The 'else' path never releases, so it also leaks (OWN001).
// Good for `python -m ownlang cfg examples/bad_maybe_release.own`.
fn use_after_maybe(flag: int) {
let b = acquire Buffer(flag);
if (flag) {
release b;
}
use b;
}
File renamed without changes.
File renamed without changes.
30 changes: 30 additions & 0 deletions examples/ok_extern_calls.own
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module ExternCalls

resource Buffer {
acquire rent
release give
}

// Host (C#) calls must declare what they do with ownership. The checker
// trusts these effect annotations and nothing else: an undeclared call that
// is handed an owned value is a hard OWN040. Borrow params are noescape, so
// the value cannot leak out through them.
extern fn Fill(borrow_mut Buffer); // writes through the buffer, hands it back
extern fn Hash(borrow Buffer); // reads only, hands it back
extern fn Store(consume Buffer); // takes ownership; caller must not reuse

// Happy path: lend the buffer to the host mutably, then immutably, then hand
// it back ourselves. Both extern calls borrow, so 'b' is still owned after.
fn read_write(size: int) {
let b = acquire Buffer(size);
Fill(b);
Hash(b);
release b;
}

// Happy path: give the buffer to the host for good. Store consumes it, so we
// neither release nor use 'b' afterwards — either of those would be OWN002.
fn hand_off(size: int) {
let b = acquire Buffer(size);
Store(b);
}
File renamed without changes.
1 change: 1 addition & 0 deletions ownlang/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""OwnLang — a micro ownership/borrow checker PoC for .NET codegen."""
File renamed without changes.
8 changes: 8 additions & 0 deletions analysis.py → ownlang/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,14 @@ def step(self, ins, st: State) -> None:
self.err("OWN002",
f"'{ins.sym.name}' returned after it was released",
ins.line)
else:
# returning an owner is an escape (consume): it needs Own
# permission, so a live loan on it is OWN007 just like move.
shared, mut = self.loans_on(st, ins.sym)
if shared or mut:
self.err("OWN007",
f"cannot return '{ins.sym.name}' while it is "
f"borrowed", ins.line)
st.var[id(ins.sym)] = {VarState.ESCAPED}
return

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
3 changes: 3 additions & 0 deletions run_tests.py → tests/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ def codes(src: str) -> list[str]:
("move_while_borrowed",
"fn f(){ let b = acquire Buffer(1); borrow b as s { let c = move b; "
"release c; } }", ["OWN007"]),
("return_while_borrowed",
"fn f() -> Buffer { let b = acquire Buffer(1); borrow b as s "
"{ return b; } }", ["OWN007"]),
("release_while_borrowed",
"fn f(){ let b = acquire Buffer(1); borrow b as s { release b; } }",
["OWN008"]),
Expand Down