Compare commits
5 Commits
6a72fac610
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f8a82f7969 | |||
| 11d17b1c92 | |||
| 9f1b2399a8 | |||
| 558d53b0c6 | |||
| ac42d43d5d |
@@ -5,6 +5,12 @@ Publiczny manifest wspólnego workspace EDU.
|
||||
Repo opisuje serie i karty pracy dostępne dla `stemctl`. Nie przechowuje
|
||||
tokenów, lokalnych ścieżek użytkownika ani plików roboczych ucznia.
|
||||
|
||||
Widoczność karty w katalogu nie jest uprawnieniem do jej wykonania. W
|
||||
zarządzanej usłudze nauczyciel uruchamia kartę przez `teactl`, a `stemctl`
|
||||
ucznia może otworzyć i wykonać tylko wersję wskazaną bieżącym
|
||||
`CardRunGrant`. Bezpośrednie przeglądanie katalogu pozostaje funkcją
|
||||
developerską i standalone.
|
||||
|
||||
`workspace.json.series` zawiera wyłącznie aktywne serie obsługiwane przez
|
||||
`stemctl`. `workspace.json.catalog_subjects` zasila drzewo UI także seriami
|
||||
planowanymi, ale nie udostępnia ich poleceniom pobierania. Pozycję można dodać
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
"title": "Bash · Console Tools",
|
||||
"catalog_only": true,
|
||||
"cards": [
|
||||
{"id": "L01", "repo": "lab-console-busybox", "number": "01", "title": "BusyBox — the Swiss Army Knife", "status": "planned"},
|
||||
{"id": "L02", "repo": "lab-console-tmux", "number": "02", "title": "Tmux — sessions, windows and panes", "status": "planned"},
|
||||
{"id": "L03", "repo": "lab-console-neovim", "number": "03", "title": "Neovim — navigation and editing", "status": "planned"},
|
||||
{"id": "L04", "repo": "lab-console-git-basics-1", "number": "04", "title": "Git Basics I — status, add and commit", "status": "planned"},
|
||||
{"id": "L05", "repo": "lab-console-git-basics-2", "number": "05", "title": "Git Basics II — log, diff and restore", "status": "planned"},
|
||||
{"id": "L06", "repo": "lab-console-git-branching-1", "number": "06", "title": "Git Branching I — branch, switch and merge", "status": "planned"},
|
||||
{"id": "L07", "repo": "lab-console-git-branching-2", "number": "07", "title": "Git Branching II — rebase and conflicts", "status": "planned"},
|
||||
{"id": "L08", "repo": "lab-console-docker", "number": "08", "title": "Docker Fundamentals", "status": "planned"}
|
||||
{"id": "L01", "repo": "lab-console-busybox", "number": "01", "title": "BusyBox — the Swiss Army Knife", "status": "existing"},
|
||||
{"id": "L02", "repo": "lab-console-tmux", "number": "02", "title": "Tmux — sessions, windows and panes", "status": "existing"},
|
||||
{"id": "L03", "repo": "lab-console-neovim", "number": "03", "title": "Neovim — navigation and editing", "status": "existing"},
|
||||
{"id": "L04", "repo": "lab-console-git-basics-1", "number": "04", "title": "Git Basics I — status, add and commit", "status": "existing"},
|
||||
{"id": "L05", "repo": "lab-console-git-basics-2", "number": "05", "title": "Git Basics II — log, diff and restore", "status": "existing"},
|
||||
{"id": "L06", "repo": "lab-console-git-branching-1", "number": "06", "title": "Git Branching I — branch, switch and merge", "status": "existing"},
|
||||
{"id": "L07", "repo": "lab-console-git-branching-2", "number": "07", "title": "Git Branching II — rebase and conflicts", "status": "existing"},
|
||||
{"id": "L08", "repo": "lab-console-docker", "number": "08", "title": "Docker Fundamentals", "status": "existing"}
|
||||
]
|
||||
}
|
||||
|
||||
+12
-17
@@ -1,22 +1,17 @@
|
||||
{
|
||||
"id": "cpp",
|
||||
"title": "C++",
|
||||
"catalog_only": true,
|
||||
"title": "C++ · Rok 2 · Semestr 1",
|
||||
"catalog_only": false,
|
||||
"cards": [
|
||||
{"id": "CPP01", "repo": "lab-cpp-build-namespaces", "number": "01", "title": "Translation Units, Linkage and Namespaces", "status": "planned"},
|
||||
{"id": "CPP02", "repo": "lab-cpp-classes-invariants", "number": "02", "title": "Classes, Encapsulation and Invariants", "status": "planned"},
|
||||
{"id": "CPP03", "repo": "lab-cpp-lifetime-raii", "number": "03", "title": "Construction, Destruction and RAII", "status": "planned"},
|
||||
{"id": "CPP04", "repo": "lab-cpp-references-const", "number": "04", "title": "References, const and Value Categories", "status": "planned"},
|
||||
{"id": "CPP05", "repo": "lab-cpp-copy-move", "number": "05", "title": "Copy, Move and the Rule of Zero/Five", "status": "planned"},
|
||||
{"id": "CPP06", "repo": "lab-cpp-ownership", "number": "06", "title": "Ownership and Resource Types", "status": "planned"},
|
||||
{"id": "CPP07", "repo": "lab-cpp-templates", "number": "07", "title": "Function and Class Templates", "status": "planned"},
|
||||
{"id": "CPP08", "repo": "lab-cpp-static-polymorphism", "number": "08", "title": "Static Polymorphism and CRTP", "status": "planned"},
|
||||
{"id": "CPP09", "repo": "lab-cpp-dynamic-polymorphism", "number": "09", "title": "Inheritance, Interfaces and Dynamic Dispatch", "status": "planned"},
|
||||
{"id": "CPP10", "repo": "lab-cpp-strong-types", "number": "10", "title": "Operator Overloading and Strong Types", "status": "planned"},
|
||||
{"id": "CPP11", "repo": "lab-cpp-containers-iterators", "number": "11", "title": "Containers, Iterators and Algorithms", "status": "planned"},
|
||||
{"id": "CPP12", "repo": "lab-cpp-lambdas-callables", "number": "12", "title": "Lambdas, Function Objects and Callables", "status": "planned"},
|
||||
{"id": "CPP13", "repo": "lab-cpp-error-models", "number": "13", "title": "Error Models with and without Exceptions", "status": "planned"},
|
||||
{"id": "CPP14", "repo": "lab-cpp-abi-evidence", "number": "14", "title": "Object Layout, ABI and Binary Evidence", "status": "planned"},
|
||||
{"id": "CPP15", "repo": "lab-cpp-resource-integration", "number": "15", "title": "Resource-type Integration Project", "status": "planned"}
|
||||
{"id": "CPP01", "repo": "lab-cpp-build-namespaces", "number": "01", "title": "Oddzielna kompilacja, linkage i przestrzenie nazw", "status": "existing"},
|
||||
{"id": "CPP02", "repo": "lab-cpp-types-initialization", "number": "02", "title": "Typy, inicjalizacja, auto, const i enum class", "status": "existing"},
|
||||
{"id": "CPP03", "repo": "lab-cpp-pointers-references", "number": "03", "title": "Wskaźniki, referencje, tablice i nullptr", "status": "existing"},
|
||||
{"id": "CPP04", "repo": "lab-cpp-functions-overloading", "number": "04", "title": "Funkcje, przeciążanie i modułowość", "status": "existing"},
|
||||
{"id": "CPP05", "repo": "lab-cpp-classes-objects", "number": "05", "title": "Klasa i obiekt: interfejs oraz implementacja", "status": "existing"},
|
||||
{"id": "CPP06", "repo": "lab-cpp-invariants", "number": "06", "title": "Hermetyzacja, niezmienniki i odpowiedzialność klasy", "status": "existing"},
|
||||
{"id": "CPP07", "repo": "lab-cpp-construction-destruction", "number": "07", "title": "Konstruktory, destruktory i inicjalizacja obiektu", "status": "existing"},
|
||||
{"id": "CPP08", "repo": "lab-cpp-scope-lifetime", "number": "08", "title": "Zakres i czas życia obiektów", "status": "existing"},
|
||||
{"id": "CPP09", "repo": "lab-cpp-raii", "number": "09", "title": "RAII i zasób związany z czasem życia", "status": "existing"},
|
||||
{"id": "CPP10", "repo": "lab-cpp-copy-move", "number": "10", "title": "Kopiowanie, przenoszenie i Rule of Zero/Five", "status": "existing"}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"title": "FreeRTOS C",
|
||||
"catalog_only": true,
|
||||
"cards": [
|
||||
{"id": "FC01", "repo": "lab-rv32i-freertos-heap4", "number": "01", "title": "heap_1–heap_5 and heap_4 mechanics", "status": "existing"},
|
||||
{"id": "FC01", "repo": "lab-rv32i-freertos-heap4", "number": "01", "title": "heap_4: From Linear Cursor to Reusable Blocks", "status": "existing"},
|
||||
{"id": "FC02", "repo": "lab-rv32i-freertos-c-first-task", "number": "02", "title": "First Task, TCB and Task Stack", "status": "existing"},
|
||||
{"id": "FC03", "repo": "lab-rv32i-freertos-c-scheduler", "number": "03", "title": "Tick, Scheduler, Priorities and Time Slicing", "status": "existing"},
|
||||
{"id": "FC04", "repo": "lab-rv32i-freertos-c-delay-state", "number": "04", "title": "Delay, Blocking and Task States", "status": "existing"},
|
||||
@@ -14,9 +14,9 @@
|
||||
{"id": "FC09", "repo": "lab-rv32i-freertos-c-event-groups", "number": "09", "title": "Event Groups and Multi-event Synchronization", "status": "existing"},
|
||||
{"id": "FC10", "repo": "lab-rv32i-freertos-c-notifications", "number": "10", "title": "Direct-to-task Notifications", "status": "existing"},
|
||||
{"id": "FC11", "repo": "lab-rv32i-freertos-c-static-allocation", "number": "11", "title": "Static Allocation and Bounded Storage", "status": "existing"},
|
||||
{"id": "FC12", "repo": "lab-rv32i-freertos-c-diagnostics", "number": "12", "title": "Assertions, Hooks, Stack Checks and Runtime Diagnostics", "status": "planned"},
|
||||
{"id": "FC13", "repo": "lab-rv32i-freertos-c-uart", "number": "13", "title": "UART Interrupt-to-task Pipeline", "status": "planned"},
|
||||
{"id": "FC14", "repo": "lab-rv32i-freertos-c-gpio-timer", "number": "14", "title": "GPIO, Hardware Timer and Deferred Work", "status": "planned"},
|
||||
{"id": "FC15", "repo": "lab-rv32i-freertos-c-integration", "number": "15", "title": "Integrated Deterministic FreeRTOS C Application", "status": "planned"}
|
||||
{"id": "FC12", "repo": "lab-rv32i-freertos-c-diagnostics", "number": "12", "title": "Assertions, Hooks, Stack Checks and Runtime Diagnostics", "status": "existing"},
|
||||
{"id": "FC13", "repo": "lab-rv32i-freertos-c-uart", "number": "13", "title": "UART Interrupt-to-task Pipeline", "status": "existing"},
|
||||
{"id": "FC14", "repo": "lab-rv32i-freertos-c-gpio-timer", "number": "14", "title": "GPIO, Hardware Timer and Deferred Work", "status": "existing"},
|
||||
{"id": "FC15", "repo": "lab-rv32i-freertos-c-integration", "number": "15", "title": "Integrated Deterministic FreeRTOS C Application", "status": "existing"}
|
||||
]
|
||||
}
|
||||
|
||||
+15
-15
@@ -3,20 +3,20 @@
|
||||
"title": "FreeRTOS C++",
|
||||
"catalog_only": true,
|
||||
"cards": [
|
||||
{"id": "K02", "repo": "lab-rv32i-freertos-task-stack-vector", "number": "02", "title": "First Task, Stack, Tick, Scheduler and Vector V0", "status": "existing"},
|
||||
{"id": "K03", "repo": "lab-rv32i-freertos-vector-raii", "number": "03", "title": "Vector V1 — Destructor, Move, Ownership and RAII", "status": "planned"},
|
||||
{"id": "K04", "repo": "lab-rv32i-freertos-scheduler-states", "number": "04", "title": "Scheduler States, Priorities and Typed Ticks", "status": "planned"},
|
||||
{"id": "K05", "repo": "lab-rv32i-freertos-heap-models", "number": "05", "title": "C++ Heap Bridge, Heap Models and HeapStats", "status": "planned"},
|
||||
{"id": "K06", "repo": "lab-rv32i-freertos-allocator-resource", "number": "06", "title": "MemoryResource and FreeRtosAllocator<T>", "status": "planned"},
|
||||
{"id": "K07", "repo": "lab-rv32i-freertos-task-wrapper", "number": "07", "title": "TaskHandle_t, Explicit Start and Static Trampoline", "status": "planned"},
|
||||
{"id": "K08", "repo": "lab-rv32i-freertos-static-task", "number": "08", "title": "DynamicTask, StaticTask, Deletion and Lifetime", "status": "planned"},
|
||||
{"id": "K09", "repo": "lab-rv32i-freertos-kernel-facade", "number": "09", "title": "Scheduler Facade and Scoped Kernel Guards", "status": "planned"},
|
||||
{"id": "K10", "repo": "lab-rv32i-freertos-queue", "number": "10", "title": "Queue<T> and StaticQueue<T, N>", "status": "planned"},
|
||||
{"id": "K11", "repo": "lab-rv32i-freertos-mutex", "number": "11", "title": "Mutex, LockGuard and Priority Inheritance", "status": "planned"},
|
||||
{"id": "K12", "repo": "lab-rv32i-freertos-semaphore-notify", "number": "12", "title": "Semaphores and Task Notifications", "status": "planned"},
|
||||
{"id": "K13", "repo": "lab-rv32i-freertos-event-group", "number": "13", "title": "EventGroup and Coordinated State", "status": "planned"},
|
||||
{"id": "K14", "repo": "lab-rv32i-freertos-sw-timer", "number": "14", "title": "Software Timer and the Timer Daemon Task", "status": "planned"},
|
||||
{"id": "K15", "repo": "lab-rv32i-freertos-isr-drivers", "number": "15", "title": "Explicit FromISR, UART and GPIO Wrappers", "status": "planned"},
|
||||
{"id": "K16", "repo": "lab-rv32i-freertos-integration", "number": "16", "title": "Integrated Real-time Application and Evidence", "status": "planned"}
|
||||
{"id": "K02", "repo": "lab-rv32i-freertos-task-stack-vector", "number": "02", "title": "C++ Task<Derived> Wrapper, CRTP and Lifecycle", "status": "existing"},
|
||||
{"id": "K03", "repo": "lab-rv32i-freertos-vector-raii", "number": "03", "title": "Vector V1 — Destructor, Move, Ownership and RAII", "status": "existing"},
|
||||
{"id": "K04", "repo": "lab-rv32i-freertos-scheduler-states", "number": "04", "title": "Scheduler States, Priorities and Typed Ticks", "status": "existing"},
|
||||
{"id": "K05", "repo": "lab-rv32i-freertos-heap-models", "number": "05", "title": "C++ Heap Bridge, Heap Models and HeapStats", "status": "existing"},
|
||||
{"id": "K06", "repo": "lab-rv32i-freertos-allocator-resource", "number": "06", "title": "MemoryResource and FreeRtosAllocator<T>", "status": "existing"},
|
||||
{"id": "K07", "repo": "lab-rv32i-freertos-task-wrapper", "number": "07", "title": "TaskHandle_t, Explicit Start and Static Trampoline", "status": "existing"},
|
||||
{"id": "K08", "repo": "lab-rv32i-freertos-static-task", "number": "08", "title": "DynamicTask, StaticTask, Deletion and Lifetime", "status": "existing"},
|
||||
{"id": "K09", "repo": "lab-rv32i-freertos-kernel-facade", "number": "09", "title": "Scheduler Facade and Scoped Kernel Guards", "status": "existing"},
|
||||
{"id": "K10", "repo": "lab-rv32i-freertos-queue", "number": "10", "title": "Queue<T> and StaticQueue<T, N>", "status": "existing"},
|
||||
{"id": "K11", "repo": "lab-rv32i-freertos-mutex", "number": "11", "title": "Mutex, LockGuard and Priority Inheritance", "status": "existing"},
|
||||
{"id": "K12", "repo": "lab-rv32i-freertos-semaphore-notify", "number": "12", "title": "Semaphores and Task Notifications", "status": "existing"},
|
||||
{"id": "K13", "repo": "lab-rv32i-freertos-event-group", "number": "13", "title": "EventGroup and Coordinated State", "status": "existing"},
|
||||
{"id": "K14", "repo": "lab-rv32i-freertos-sw-timer", "number": "14", "title": "Software Timer and the Timer Daemon Task", "status": "existing"},
|
||||
{"id": "K15", "repo": "lab-rv32i-freertos-isr-drivers", "number": "15", "title": "Explicit FromISR, UART and GPIO Wrappers", "status": "existing"},
|
||||
{"id": "K16", "repo": "lab-rv32i-freertos-integration", "number": "16", "title": "Integrated Real-time Application and Evidence", "status": "existing"}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
"title": "ASM · RV32I From Blinker to RISC-V",
|
||||
"catalog_only": true,
|
||||
"cards": [
|
||||
{"id": "L01", "repo": "lab-rv32i-asm-number-systems", "number": "01", "title": "Number Systems and Storage", "status": "planned"},
|
||||
{"id": "L02", "repo": "lab-rv32i-asm-fpga-bringup", "number": "02", "title": "FPGA Bring-up and Programming", "status": "planned"},
|
||||
{"id": "L03", "repo": "lab-rv32i-asm-blinker", "number": "03", "title": "Blinker and Synchronous Logic", "status": "planned"},
|
||||
{"id": "L04", "repo": "lab-rv32i-asm-decoder", "number": "04", "title": "The RISC-V ISA and Instruction Decoder", "status": "planned"},
|
||||
{"id": "L05", "repo": "lab-rv32i-asm-alu", "number": "05", "title": "ALU and the Verilog Assembler", "status": "planned"},
|
||||
{"id": "L06", "repo": "lab-rv32i-asm-control-flow", "number": "06", "title": "Control Flow — Jumps and Branches", "status": "planned"},
|
||||
{"id": "L07", "repo": "lab-rv32i-asm-addresses-memory", "number": "07", "title": "Addresses and Memory", "status": "planned"},
|
||||
{"id": "L08", "repo": "lab-rv32i-asm-subroutines-abi", "number": "08", "title": "Subroutines and the RISC-V ABI", "status": "planned"},
|
||||
{"id": "L09", "repo": "lab-rv32i-asm-load-store", "number": "09", "title": "Load and Store", "status": "planned"}
|
||||
{"id": "L01", "repo": "lab-rv32i-asm-number-systems", "number": "01", "title": "Number Systems and Storage", "status": "existing"},
|
||||
{"id": "L02", "repo": "lab-rv32i-asm-fpga-bringup", "number": "02", "title": "FPGA Bring-up and Programming", "status": "existing"},
|
||||
{"id": "L03", "repo": "lab-rv32i-asm-blinker", "number": "03", "title": "Blinker and Synchronous Logic", "status": "existing"},
|
||||
{"id": "L04", "repo": "lab-rv32i-asm-decoder", "number": "04", "title": "The RISC-V ISA and Instruction Decoder", "status": "existing"},
|
||||
{"id": "L05", "repo": "lab-rv32i-asm-alu", "number": "05", "title": "ALU and the Verilog Assembler", "status": "existing"},
|
||||
{"id": "L06", "repo": "lab-rv32i-asm-control-flow", "number": "06", "title": "Control Flow — Jumps and Branches", "status": "existing"},
|
||||
{"id": "L07", "repo": "lab-rv32i-asm-addresses-memory", "number": "07", "title": "Addresses and Memory", "status": "existing"},
|
||||
{"id": "L08", "repo": "lab-rv32i-asm-subroutines-abi", "number": "08", "title": "Subroutines and ABI", "status": "existing"},
|
||||
{"id": "L09", "repo": "lab-rv32i-asm-load-store", "number": "09", "title": "Load and Store Semantics", "status": "existing"}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ INF · Informatyka
|
||||
│ ├── ASM · RV32I From Blinker to RISC-V [9]
|
||||
│ └── C · Freestanding RV32I and K&R [13]
|
||||
├── Rok 2
|
||||
│ ├── C++ [15]
|
||||
│ ├── C++ · semestr 1 [10 active]
|
||||
│ ├── C++ · semestr 2 [10 planned]
|
||||
│ ├── FreeRTOS C [15]
|
||||
│ ├── FreeRTOS C++ [15]
|
||||
│ ├── POSIX Threads [15]
|
||||
@@ -29,10 +30,11 @@ INF · Informatyka
|
||||
```
|
||||
|
||||
Pierwszy blok zawiera dokładnie 30 tematów: Bash 8 + ASM 9 + C 13.
|
||||
Drugi blok zawiera dokładnie 60 tematów: FreeRTOS C 15 + C++ 15 + FreeRTOS
|
||||
C++ 15 + POSIX Threads 15. OOP and Design Patterns jest osobnym kursem i nie
|
||||
jest wliczany do tych 60. `std::thread`/`std::jthread` i Boost.Asio są kolejnym
|
||||
etapem i nie są jeszcze częścią tego katalogu.
|
||||
Drugi rok zawiera dwusemestralny kurs teoretyczny C++ (10 + 10 lekcji) oraz
|
||||
osobne serie laboratoryjne FreeRTOS C, FreeRTOS C++ i POSIX Threads po 15
|
||||
kart. OOP and Design Patterns jest osobnym kursem odniesienia. Aktywna seria
|
||||
`cpp` obejmuje obecnie komplet pierwszego semestru. Biblioteka standardowa,
|
||||
`std::thread`/`std::jthread` i Boost.Asio należą do kolejnych semestrów.
|
||||
|
||||
Kolejność stosowania języków jest jawna:
|
||||
|
||||
|
||||
+58
-1
@@ -1,6 +1,6 @@
|
||||
# C — Freestanding RV32I and K&R
|
||||
|
||||
Status: 8 kart istniejących lub rozpoczętych, 5 planowanych.
|
||||
Status: C01–C13 gotowe; seria C zakończona przed rozpoczęciem serii C++.
|
||||
|
||||
```text
|
||||
C · Freestanding RV32I and K&R
|
||||
@@ -23,5 +23,62 @@ RV32I ASM jest osobną serią-prerekwizytem. C01–C03 tworzą przejście z
|
||||
freestanding assemblera do środowiska C, ale pozostają kartami serii C,
|
||||
ponieważ ich wynikiem jest rozumienie uruchomienia i ABI programu C.
|
||||
|
||||
## Układ każdego przykładu: A1–A8
|
||||
|
||||
Każdy przykład źródłowy w karcie serii C jest osobnym taskiem i jawnie
|
||||
odpowiada na komplet pytań A1–A8:
|
||||
|
||||
```text
|
||||
A1 CONTEXT granica systemu i odpowiedzialność przykładu
|
||||
A2 STRUCTURE typy, obiekty, reprezentacja i ownership
|
||||
A3 DISPATCH granica wywołania, callbacku albo ISR
|
||||
A4 APPLICATION konkretne funkcje, dane i inwariant przykładu
|
||||
A5 FLOW kolejność wykonania oraz checkpointy
|
||||
A6 STATE stan, lifetime i przejścia wartości
|
||||
A7 RUNTIME ABI, rejestry, adresy, sekcje ELF i wynik pomiaru
|
||||
A8 PATTERNS nazwana, rzeczywiście wielokrotnego użytku decyzja
|
||||
```
|
||||
|
||||
A1–A8 jest profilem pytań, a nie nakazem tworzenia ośmiu dekoracyjnych
|
||||
diagramów. Każda pozycja ma status `enabled` albo `unavailable`. Widok
|
||||
`enabled` musi wnosić odrębny dowód; `unavailable` zawiera konkretny powód.
|
||||
Wartościowy opis tekstowy jest pełnoprawnym widokiem. Diagram powstaje tylko
|
||||
wtedy, gdy relacja, kolejność lub stan są mniej czytelne w krótkim tekście.
|
||||
|
||||
Dla C04–C06 nowe źródło JSON, TeX, HTML i nowy PDF są dodawane obok
|
||||
historycznych kart. Oryginalne `doc/main.tex`, PDF-y oraz przykłady w
|
||||
`src/tasks/` pozostają niezmienionym materiałem referencyjnym.
|
||||
|
||||
Pełne cele C10–C13 i granica roku znajdują się w
|
||||
`series/inf/lab-rv32i-c-pointers-arrays/guidelines/year-01-interrupts-to-year-02-freertos.md`.
|
||||
|
||||
## Stan odbioru serii C — 2026-07-20
|
||||
|
||||
Każda karta ma wygenerowane źródło JSON, widok web i nowy PDF. Odbiór
|
||||
potwierdza dokładną kolejność A1–A8 w każdym tasku, jawne uzasadnienie każdego
|
||||
N/D, poprawny JSON i JavaScript, poprawność PDF według `qpdf` oraz brak pustych,
|
||||
anonimowych i przepełnionych stron. Przykłady uruchamialne przeszły właściwe
|
||||
testy hostowe i/lub wyrocznie Hazard3.
|
||||
|
||||
```text
|
||||
karta przykłady bloki A1–A8
|
||||
C01 3 24
|
||||
C02 4 32
|
||||
C03 2 16
|
||||
C04 12 96
|
||||
C05 8 64
|
||||
C06 11 88
|
||||
C07 12 96
|
||||
C08 4 32
|
||||
C09 5 40
|
||||
C10 3 24
|
||||
C11 3 24
|
||||
C12 3 24
|
||||
C13 4 32
|
||||
RAZEM 74 592
|
||||
```
|
||||
|
||||
PDF-y mają łącznie 180 stron. Spośród 592 widoków 508 ma stan `enabled`, a 84
|
||||
ma stan `unavailable` z konkretnym powodem. Historyczne źródła C04–C06 nadal są
|
||||
materiałem referencyjnym: nowy układ nie nadpisuje `doc/main.tex`, starych
|
||||
PDF-ów ani przykładów w `src/tasks/`.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Bash · Console Tools — plan kart
|
||||
|
||||
Status: plan, 8 lekcji.
|
||||
Status: L01–L08 gotowe; seria zakończona i odbierana w profilu
|
||||
`native-amd64` przez `stemctl`.
|
||||
|
||||
Seria przygotowuje warsztat przed FPGA, assemblerem i C. Nazwa obejmuje pracę
|
||||
w powłoce i terminalu; BusyBox może udostępniać `ash`, więc nie utożsamiamy
|
||||
@@ -18,8 +19,53 @@ Bash · Console Tools
|
||||
└── L08 · Docker Fundamentals
|
||||
```
|
||||
|
||||
Każda karta kończy się małym dowodem wykonania: komendą, stanem terminala albo
|
||||
historią Git, którą uczeń potrafi odtworzyć i wyjaśnić.
|
||||
Każda karta zawiera trzy wykonywalne taski. Repozytorium karty dostarcza
|
||||
kontrakt `stem-card.yaml`, testy stanu, wygenerowany widok React, dwustronicowy
|
||||
PDF A4 oraz akcje `build`, `test`, `run` i `debug`. Debug zapisuje
|
||||
`trace.log` w katalogu artefaktów tasku.
|
||||
|
||||
## Stan odbioru serii — 2026-07-21
|
||||
|
||||
| Karta | Dowód końcowy |
|
||||
| --- | --- |
|
||||
| L01 BusyBox | dispatch multicall, operacje plikowe, proces i host |
|
||||
| L02 Tmux | sesja, okna i panele, zachowanie stanu po detach/attach |
|
||||
| L03 Neovim | nawigacja, search/edit/save, undo/redo |
|
||||
| L04 Git Basics I | init, status/add, pierwszy commit i clean |
|
||||
| L05 Git Basics II | log, diff staged/worktree, bezpieczne restore |
|
||||
| L06 Git Branching I | branch/switch, rozbieżność, merge commit |
|
||||
| L07 Git Branching II | rebase, rzeczywisty konflikt UU, liniowa historia |
|
||||
| L08 Docker | specyfikacja image, lifecycle, volume i bind mount |
|
||||
|
||||
Wszystkie 24 taski przechodzą w kontenerze `native-amd64`. Każdy task pracuje
|
||||
w izolowanym katalogu tymczasowym i raportuje mierzalny komunikat `PASS`.
|
||||
|
||||
### Granice środowiska
|
||||
|
||||
Obraz `native-amd64` nie zawiera BusyBox. L01 używa więc audytowalnego
|
||||
fixture C implementującego wyłącznie ćwiczony mechanizm multicall, wykrywa
|
||||
prawdziwy BusyBox, gdy jest dostępny, i zawsze raportuje użyty backend. Fixture
|
||||
nie jest przedstawiany jako binarka BusyBox.
|
||||
|
||||
Profil ucznia nie otrzymuje socketu Docker/Podman. L08 używa jawnego modelu
|
||||
stanów offline do sprawdzenia semantyki image/container/storage. Jego `PASS`
|
||||
nie oznacza uruchomienia prawdziwego silnika. Powtórzenie ćwiczenia z realnym
|
||||
CLI należy wykonać na kontrolowanej maszynie operatorskiej, najlepiej z
|
||||
rootless Podmanem albo Dockerem, bez montowania socketu do kontenera ucznia.
|
||||
|
||||
### Sposób uruchamiania
|
||||
|
||||
```bash
|
||||
stemctl series show console-bash
|
||||
stemctl list-cards console-bash
|
||||
stemctl card use console-bash L01
|
||||
stemctl test native-amd64 console-bash L01 1
|
||||
stemctl debug native-amd64 console-bash L01 3
|
||||
```
|
||||
|
||||
Numer karty i tasku można podmienić na dowolne L01–L08 i 1–3. Identyfikatory,
|
||||
repozytoria i kolejność kart są zapisane w `series/console-bash.json`, a stan
|
||||
realizacji w `catalog/console-bash.json`.
|
||||
|
||||
Pierwotne ustalenia znajdują się również w
|
||||
`series/inf/lab-rv32i-c-pointers-arrays/guidelines/console-series.md`.
|
||||
|
||||
+49
-26
@@ -1,32 +1,55 @@
|
||||
# C++ — plan kart
|
||||
# C++ — plan wielosemestralny i stan wdrożenia
|
||||
|
||||
Status: plan, 15 tematów.
|
||||
Źródło zakresu: `/home/user/dev/keys/cxx.md`. Standard kursu: C++20 z
|
||||
wybranymi, jawnie oznaczonymi elementami C++23. Cykl obejmuje 53 lekcje
|
||||
teoretyczne. Projekty, FreeRTOS i praca na urządzeniu pozostają osobnymi
|
||||
zajęciami.
|
||||
|
||||
Seria uczy języka i modelu obiektu bez zależności od RTOS. Dopiero po niej
|
||||
uczeń przechodzi do FreeRTOS C++ i rozpoznaje, które zachowanie pochodzi z C++,
|
||||
a które z wrappera lub kernela. Kurs może być prowadzony równolegle z
|
||||
FreeRTOS C, ponieważ oba mają wspólny ukończony prerekwizyt C.
|
||||
| Etap | Lekcje | Oś merytoryczna | Stan |
|
||||
| --- | ---: | --- | --- |
|
||||
| Rok 2, semestr 1 | 10 | fundamenty języka, klasy, czas życia i RAII | **wdrożony** |
|
||||
| Rok 2, semestr 2 | 10 | OOP i C++ w systemach wbudowanych | plan |
|
||||
| Rok 3, semestr 1 | 16 | STL i biblioteka standardowa | plan |
|
||||
| Rok 3, semestr 2 | 17 | współbieżność, korutyny i Boost.Asio | plan |
|
||||
|
||||
## Rok 2, semestr 1 — aktywna seria `cpp`
|
||||
|
||||
Książka prowadząca: Bjarne Stroustrup, *A Tour of C++, 3rd Edition*.
|
||||
*The C++ Programming Language, 4th Edition* jest źródłem uzupełniającym dla
|
||||
nauczyciela. Karty parafrazują pojęcia i zawierają własne eksperymenty; nie
|
||||
kopiują treści książek.
|
||||
|
||||
```text
|
||||
C++
|
||||
├── CPP01 · Translation Units, Linkage and Namespaces
|
||||
├── CPP02 · Classes, Encapsulation and Invariants
|
||||
├── CPP03 · Construction, Destruction and RAII
|
||||
├── CPP04 · References, const and Value Categories
|
||||
├── CPP05 · Copy, Move and the Rule of Zero/Five
|
||||
├── CPP06 · Ownership and Resource Types
|
||||
├── CPP07 · Function and Class Templates
|
||||
├── CPP08 · Static Polymorphism and CRTP
|
||||
├── CPP09 · Inheritance, Interfaces and Dynamic Dispatch
|
||||
├── CPP10 · Operator Overloading and Strong Types
|
||||
├── CPP11 · Containers, Iterators and Algorithms
|
||||
├── CPP12 · Lambdas, Function Objects and Callables
|
||||
├── CPP13 · Error Models with and without Exceptions
|
||||
├── CPP14 · Object Layout, ABI and Binary Evidence
|
||||
└── CPP15 · Resource-type Integration Project
|
||||
C++ · Rok 2 · Semestr 1
|
||||
├── CPP01 · Oddzielna kompilacja, deklaracja, definicja, linkage i namespace
|
||||
├── CPP02 · Typy, inicjalizacja, auto, const, enum class i typ użytkownika
|
||||
├── CPP03 · Wskaźniki, referencje, tablice, nullptr i argumenty
|
||||
├── CPP04 · Funkcje, przeciążanie, wartości zwracane, zakres i modułowość
|
||||
├── CPP05 · Klasa i obiekt: pola, metody, dostęp, interfejs i implementacja
|
||||
├── CPP06 · Hermetyzacja, niezmienniki i odpowiedzialność klasy
|
||||
├── CPP07 · Konstruktory, destruktory i inicjalizacja obiektu
|
||||
├── CPP08 · Zakres i czas życia obiektów automatycznych, statycznych i dynamicznych
|
||||
├── CPP09 · RAII i powiązanie zasobu z czasem życia obiektu
|
||||
└── CPP10 · Kopiowanie, przenoszenie, Rule of Zero/Five i własność zasobu
|
||||
```
|
||||
|
||||
Kurs OOP/wzorców pozostaje osobną serią. Karty C++ mogą przygotowywać potrzebny
|
||||
mechanizm, ale nie udają, że każda cecha języka jest wzorcem GoF. Gdy w kodzie
|
||||
pojawia się rzeczywisty problem projektowy, karta C++ linkuje do odpowiedniej
|
||||
karty OOP jako rozwinięcia decyzji.
|
||||
Każda karta ma trzy niezależne programy, kompilację
|
||||
`-std=c++20 -Wall -Wextra -Wpedantic -Werror`, dokładny kontrakt stdout,
|
||||
testy Node, widok React, PDF A4 i akcje `build/test/run/debug` dla profilu
|
||||
`native-amd64`. Generator źródeł znajduje się w
|
||||
`tools/generate_cpp_y2s1.py` tego repozytorium.
|
||||
|
||||
## Granice kolejnych semestrów
|
||||
|
||||
- Semestr 2 rozpoczyna się od typów wartościowych i operatorów, a kończy
|
||||
teorią wrapperów `Task`, `StaticQueue<T,N>`, `Mutex` i `LockGuard`.
|
||||
- Rok 3, semestr 1 należy do STL: kontenery, iteratory, algorytmy, ranges,
|
||||
typy pomocnicze, smart pointery i narzędzia biblioteki standardowej.
|
||||
- Rok 3, semestr 2 obejmuje `thread`/`jthread`, synchronizację, atomiki,
|
||||
futures, korutyny i Boost.Asio.
|
||||
- Szczegóły API FreeRTOS, portu, ISR i uruchamiania na płytce pozostają w
|
||||
seriach FreeRTOS C oraz FreeRTOS C++.
|
||||
|
||||
Kurs OOP/wzorców jest osobną serią odniesienia. Karta C++ linkuje do niej
|
||||
dopiero wtedy, gdy występuje rzeczywisty problem projektowy, a nie tylko
|
||||
pojedynczy mechanizm języka.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# FreeRTOS C — book-led card sequence
|
||||
|
||||
Status: FC01–FC02 exist; FC03 is the next implementation; FC04–FC15 are
|
||||
planned. This series uses only the FreeRTOS C API. C++ wrappers belong to a
|
||||
later, separate series.
|
||||
Status: FC01–FC15 istnieją; blok 15 kart FreeRTOS C jest kompletny i stanowi
|
||||
zamknięty fundament przed serią FreeRTOS C++. Każda karta używa publicznego
|
||||
API C, a końcowa FC15 scala mechanizmy w jeden deterministyczny eksperyment.
|
||||
|
||||
## Primary source and ordering rule
|
||||
|
||||
@@ -62,7 +62,7 @@ simulator.
|
||||
|
||||
```text
|
||||
FreeRTOS C — 15 cards
|
||||
├── FC01 · Heap schemes and heap_4 block mechanics
|
||||
├── FC01 · heap_4: from a linear cursor to reusable blocks
|
||||
├── FC02 · First task, typed context, TCB and task stack
|
||||
├── FC03 · Tick, priorities, preemption and time slicing
|
||||
├── FC04 · Delay, blocking, task states and deletion
|
||||
@@ -79,22 +79,37 @@ FreeRTOS C — 15 cards
|
||||
└── FC15 · Integrated deterministic FreeRTOS C application
|
||||
```
|
||||
|
||||
## FC01 — Heap schemes and heap_4 block mechanics
|
||||
## FC01 — `heap_4`: from a linear cursor to reusable blocks
|
||||
|
||||
**Book basis:** 3.1–3.4: `heap_1`–`heap_5`, heap utilities, allocation
|
||||
failure and static allocation introduction.
|
||||
**Duration:** one 30-minute lesson.
|
||||
|
||||
**Direct predecessor:** C07, K&R 5.4 Task04 — `allocbuf[64]`, `allocp`,
|
||||
`alloc(5)`, `alloc(7)` and cursor offsets `0 -> 5 -> 12`.
|
||||
|
||||
**Book basis:** the `heap_4` and heap-statistics parts of Chapter 3. The other
|
||||
FreeRTOS heap implementations are a one-minute map of alternatives, not
|
||||
parallel lesson content.
|
||||
|
||||
- Opening problem: the linear project cannot release the first 5-byte area
|
||||
while preserving the later 7-byte area, cannot remember reusable holes and
|
||||
recovers the arena only with a whole-arena reset.
|
||||
- New model: a block header, an address-ordered free list, first-fit selection,
|
||||
splitting and coalescing of physically adjacent free blocks.
|
||||
- Raw API: `pvPortMalloc`, `vPortFree`, `xPortGetFreeHeapSize`,
|
||||
`xPortGetMinimumEverFreeHeapSize`, `vPortGetHeapStats`.
|
||||
- Main task: compare allocator policies, then walk allocation, split, free
|
||||
and coalescing in `heap_4`.
|
||||
- Blocks: A1 allocator boundary; A2 block/list layout; A5 allocation flow;
|
||||
A6 free/allocated block state; A7 heap addresses and statistics.
|
||||
- Exercise: predict the free-list shape for a new allocate/free order.
|
||||
- Hazard3/GDB proof: block headers, aligned sizes and coalesced neighbors
|
||||
agree with the final heap statistics.
|
||||
- Main pitfall: treating the minimum-ever-free value as current free space or
|
||||
assuming all heap implementations support free/coalescing.
|
||||
- Task 1 and Task 2 are short teacher-led models with a student prediction;
|
||||
they are not separate build/debug sessions during the lesson.
|
||||
- Task 3 is the only central student replay: real upstream `heap_4.c`, two
|
||||
stable checkpoints, fragmentation metrics, recovery and OOM.
|
||||
- Pico 2 W supplies one prebuilt RP2350 hardware observation. `heap_4` is the
|
||||
allocator selected and linked by the project, not a hardware feature of the
|
||||
microcontroller.
|
||||
- Acceptance: the student names the three additions over the linear allocator
|
||||
(header, free list, coalescing), predicts `2 free blocks -> 1 free block`,
|
||||
and distinguishes current free bytes, largest free block and minimum-ever
|
||||
free bytes.
|
||||
- Main pitfall: assuming that a large sum of free bytes guarantees one large
|
||||
allocation, or that minimum-ever-free increases after `free`.
|
||||
|
||||
## FC02 — First task, typed context, TCB and task stack
|
||||
|
||||
@@ -367,10 +382,12 @@ Every new card must contain:
|
||||
8. HTML and TeX generated from one `card_source.json`;
|
||||
9. no PDF generation and no commit unless explicitly requested.
|
||||
|
||||
## Implementation order
|
||||
## Completed implementation order
|
||||
|
||||
```text
|
||||
FC03 scheduler
|
||||
FC01 heap_4
|
||||
→ FC02 first task
|
||||
→ FC03 scheduler
|
||||
→ FC04 state/delay
|
||||
→ FC05 queues
|
||||
→ FC06 software timers
|
||||
@@ -385,5 +402,7 @@ FC03 scheduler
|
||||
→ FC15 integration
|
||||
```
|
||||
|
||||
Ukończenie FC15 jest pierwszą z dwóch bramek wejścia do FreeRTOS C++; drugą
|
||||
jest ukończenie właściwych kart językowych C++/OOP.
|
||||
Obie bramki wejścia do FreeRTOS C++ są spełnione: FC15 zamyka tor systemowy C,
|
||||
a właściwe karty językowe C++/OOP dostarczają model własności, RAII, szablony i
|
||||
statyczne trampoline. Następnym etapem jest audyt i realizacja serii FreeRTOS
|
||||
C++ karta po karcie, bez mieszania wrapperów z implementacją kernela w C.
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
# FreeRTOS C++ — plan kart
|
||||
|
||||
Status: K02 istnieje i jest bieżącą kartą; K03–K16 są planem.
|
||||
Status: K02–K16 są gotowe; blok 15 kart jest kompletny. Każda karta ma
|
||||
freestanding build C++17, test hosta, kontrolę ABI, wykonanie na Hazard3 oraz
|
||||
sprawdzony PDF. Źródła i artefakty używają wspólnej numeracji Kxx/16.
|
||||
|
||||
Karta `heap_4` należy do serii FreeRTOS C. FreeRTOS C++ zaczyna się dopiero po
|
||||
ukończeniu dwóch torów prowadzonych równolegle: FreeRTOS C oraz C++. K02
|
||||
porównuje znany już surowy task C z freestanding wrapperem C++ i Vector V0.
|
||||
wprowadza freestanding wrapper `Task<Derived>`, CRTP i statyczny trampoline.
|
||||
K03 pokazuje krótki, celowo niepełny Vector V0 bez ukrytego wymagania wykonania
|
||||
osobnej karty, a następnie buduje z niego move-only Vector V1 z RAII.
|
||||
|
||||
```text
|
||||
FreeRTOS C++
|
||||
├── K02 · First Task, Stack, Tick, Scheduler and Vector V0
|
||||
├── K02 · C++ Task<Derived> Wrapper, CRTP and Lifecycle
|
||||
├── K03 · Vector V1 — Destructor, Move, Ownership and RAII
|
||||
├── K04 · Scheduler States, Priorities and Typed Ticks
|
||||
├── K05 · C++ Heap Bridge, Heap Models and HeapStats
|
||||
@@ -32,7 +36,7 @@ freestanding, bez wyjątków, RTTI i zależności od hosted `libstdc++`.
|
||||
Każda karta linkuje również do osobnej serii OOP, gdy wrapper rzeczywiście
|
||||
realizuje wzorzec lub idiom wymagający osobnego omówienia.
|
||||
|
||||
Szczegółowy plan bieżącej K02 oraz kontrolowane porównanie z FC02:
|
||||
Materiały wejściowe K02 oraz kontrolowane porównanie z FC02:
|
||||
|
||||
- [K02 Task01 — A1–A8 plan](../../../../series/freertos/lab-rv32i-freertos-task-stack-vector/doc/task01-a1-a8-plan.md)
|
||||
- [FC02/K02 — paired first-task experiment](freertos-first-task-a1-a8.md)
|
||||
|
||||
@@ -1,24 +1,66 @@
|
||||
# ASM · RV32I From Blinker to RISC-V
|
||||
|
||||
Status: plan, 9 lekcji.
|
||||
Status: L01--L09 opracowane, testowane i zarejestrowane; seria zakończona.
|
||||
|
||||
```text
|
||||
ASM · RV32I From Blinker to RISC-V
|
||||
├── L01 · Number Systems and Storage
|
||||
├── L02 · FPGA Bring-up and Programming
|
||||
├── L03 · Blinker and Synchronous Logic [steps 1–3]
|
||||
├── L04 · The RISC-V ISA and Instruction Decoder [steps 4–5]
|
||||
├── L05 · ALU and the Verilog Assembler [steps 6–7]
|
||||
├── L06 · Control Flow — Jumps and Branches [steps 8–9]
|
||||
├── L07 · Addresses and Memory [steps 10–11]
|
||||
├── L08 · Subroutines and the RISC-V ABI [steps 13–14]
|
||||
└── L09 · Load and Store [steps 15–16]
|
||||
├── L01 · Number Systems and Storage [existing · 3 taski]
|
||||
├── L02 · FPGA Bring-up and Programming [existing · 3 taski]
|
||||
├── L03 · Blinker and Synchronous Logic [existing · 3 taski]
|
||||
├── L04 · The RISC-V ISA and Instruction Decoder [existing · 3 taski]
|
||||
├── L05 · ALU and the Verilog Assembler [existing · 3 taski]
|
||||
├── L06 · Control Flow — Jumps and Branches [existing · 3 taski]
|
||||
├── L07 · Addresses and Memory [existing · 3 taski]
|
||||
├── L08 · Subroutines and ABI [existing · 3 taski]
|
||||
└── L09 · Load and Store Semantics [existing · 3 taski]
|
||||
```
|
||||
|
||||
L01 dostarcza języka liczb, kodowania i pamięci. L02 ustanawia fizyczną
|
||||
drabinkę FPGA. Kolejne karty prowadzą od logiki synchronicznej do rdzenia,
|
||||
który wykonuje podstawowe instrukcje RV32I. Step 12 pozostaje późniejszym
|
||||
przeglądem jakości implementacji.
|
||||
który wykonuje podstawowe instrukcje RV32I.
|
||||
|
||||
## Stan odbioru serii — 2026-07-21
|
||||
|
||||
Każda karta ma trzy wykonywalne taski, niezależny model `native-amd64`,
|
||||
self-checking SystemVerilog w profilu `hazard3-sim`, akcję debug zapisującą
|
||||
VCD, testy kontraktu i stanu, widok React oraz dwustronicowy PDF A4.
|
||||
|
||||
| Karta | Dowód końcowy |
|
||||
| --- | --- |
|
||||
| L01 | systemy pozycyjne, sign/zero extension, shifts i little-endian |
|
||||
| L02 | polaryzacja, znany reset, blinker i uporządkowany preflight FPGA |
|
||||
| L03 | clock enable, counter blinker i pattern ROM |
|
||||
| L04 | dekoder, legalność opcode i bank rejestrów |
|
||||
| L05 | ALU, kodowanie instrukcji i wykonanie małego programu |
|
||||
| L06 | warunki branch, immediate/target i ślad PC |
|
||||
| L07 | LUI/AUIPC, pamięć słów, adres i fault |
|
||||
| L08 | JAL/JALR, role ABI i zagnieżdżone powroty |
|
||||
| L09 | store strobes, rozszerzenia load i roundtrip pamięci |
|
||||
|
||||
Odbiór obejmuje 27 tasków wykonanych w obu profilach: 54/54 zakończyły się
|
||||
komunikatem `PASS`. PDF-y przechodzą `qpdf --check`, a ich pliki
|
||||
`source-commit.txt` wskazują bezpośredni commit źródłowy.
|
||||
|
||||
### Granica sprzętowa L02
|
||||
|
||||
Repozytorium L02 nie zgaduje modelu płytki, pinów ani programatora. Dostarcza
|
||||
`board/board-contract.yaml` jako bezpieczny szablon oraz osobny formularz
|
||||
dowodu fizycznego. Automatyczny preflight i symulacja zawsze raportują
|
||||
`hardware_observed=0` oraz `claim=preflight-only`; nie są przedstawiane jako
|
||||
zbudowanie bitstreamu ani zaprogramowanie FPGA. Fizyczne zaliczenie wymaga
|
||||
konkretnej płytki, SHA-256 bitstreamu, zgodnego device ID, logu konfiguracji i
|
||||
zmierzonej obserwacji LED.
|
||||
|
||||
### Sposób uruchamiania
|
||||
|
||||
```bash
|
||||
stemctl series show rv32i-asm
|
||||
stemctl list-cards rv32i-asm
|
||||
stemctl card use rv32i-asm L01
|
||||
stemctl test native-amd64 rv32i-asm L01 1
|
||||
stemctl test hazard3-sim rv32i-asm L01 1
|
||||
stemctl debug hazard3-sim rv32i-asm L01 3
|
||||
```
|
||||
|
||||
Materiał źródłowy programu:
|
||||
`series/inf/lab-rv32i-c-pointers-arrays/guidelines/year-01-interrupts-to-year-02-freertos.md`.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"id": "console-bash",
|
||||
"title": "Bash · Console Tools",
|
||||
"source_org": "edu-inf",
|
||||
"answer_org": "c2025-1a-inf",
|
||||
"source_remote": "r1",
|
||||
"answer_remote": "r1a",
|
||||
"fallback_branch": "main",
|
||||
"workspace_dir": "console",
|
||||
"source_dir": "console",
|
||||
"default_card": "L01",
|
||||
"cards": [
|
||||
{"id": "L01", "repo": "lab-console-busybox", "branch": "main", "title": "BusyBox — the Swiss Army Knife"},
|
||||
{"id": "L02", "repo": "lab-console-tmux", "branch": "main", "title": "Tmux — sessions, windows and panes"},
|
||||
{"id": "L03", "repo": "lab-console-neovim", "branch": "main", "title": "Neovim — navigation and editing"},
|
||||
{"id": "L04", "repo": "lab-console-git-basics-1", "branch": "main", "title": "Git Basics I — status, add and commit"},
|
||||
{"id": "L05", "repo": "lab-console-git-basics-2", "branch": "main", "title": "Git Basics II — log, diff and restore"},
|
||||
{"id": "L06", "repo": "lab-console-git-branching-1", "branch": "main", "title": "Git Branching I — branch, switch and merge"},
|
||||
{"id": "L07", "repo": "lab-console-git-branching-2", "branch": "main", "title": "Git Branching II — rebase and conflicts"},
|
||||
{"id": "L08", "repo": "lab-console-docker", "branch": "main", "title": "Docker Fundamentals"}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"id": "cpp",
|
||||
"title": "C++ · Rok 2 · Semestr 1",
|
||||
"source_org": "edu-cpp",
|
||||
"answer_org": "c2025-2a-inf",
|
||||
"source_remote": "r1",
|
||||
"answer_remote": "r1a",
|
||||
"fallback_branch": "main",
|
||||
"workspace_dir": "cpp",
|
||||
"source_dir": "cpp",
|
||||
"default_card": "CPP01",
|
||||
"cards": [
|
||||
{"id": "CPP01", "repo": "lab-cpp-build-namespaces", "branch": "main", "title": "Oddzielna kompilacja, linkage i przestrzenie nazw"},
|
||||
{"id": "CPP02", "repo": "lab-cpp-types-initialization", "branch": "main", "title": "Typy, inicjalizacja, auto, const i enum class"},
|
||||
{"id": "CPP03", "repo": "lab-cpp-pointers-references", "branch": "main", "title": "Wskaźniki, referencje, tablice i nullptr"},
|
||||
{"id": "CPP04", "repo": "lab-cpp-functions-overloading", "branch": "main", "title": "Funkcje, przeciążanie i modułowość"},
|
||||
{"id": "CPP05", "repo": "lab-cpp-classes-objects", "branch": "main", "title": "Klasa i obiekt: interfejs oraz implementacja"},
|
||||
{"id": "CPP06", "repo": "lab-cpp-invariants", "branch": "main", "title": "Hermetyzacja, niezmienniki i odpowiedzialność klasy"},
|
||||
{"id": "CPP07", "repo": "lab-cpp-construction-destruction", "branch": "main", "title": "Konstruktory, destruktory i inicjalizacja obiektu"},
|
||||
{"id": "CPP08", "repo": "lab-cpp-scope-lifetime", "branch": "main", "title": "Zakres i czas życia obiektów"},
|
||||
{"id": "CPP09", "repo": "lab-cpp-raii", "branch": "main", "title": "RAII i zasób związany z czasem życia"},
|
||||
{"id": "CPP10", "repo": "lab-cpp-copy-move", "branch": "main", "title": "Kopiowanie, przenoszenie i Rule of Zero/Five"}
|
||||
]
|
||||
}
|
||||
+25
-1
@@ -14,7 +14,7 @@
|
||||
"id": "FC01",
|
||||
"repo": "lab-rv32i-freertos-heap4",
|
||||
"branch": "main",
|
||||
"title": "heap_1–heap_5 and heap_4 mechanics"
|
||||
"title": "heap_4: From Linear Cursor to Reusable Blocks"
|
||||
},
|
||||
{
|
||||
"id": "FC02",
|
||||
@@ -75,6 +75,30 @@
|
||||
"repo": "lab-rv32i-freertos-c-static-allocation",
|
||||
"branch": "main",
|
||||
"title": "Static Allocation and Bounded Storage"
|
||||
},
|
||||
{
|
||||
"id": "FC12",
|
||||
"repo": "lab-rv32i-freertos-c-diagnostics",
|
||||
"branch": "main",
|
||||
"title": "Assertions, Hooks, Stack Checks and Runtime Diagnostics"
|
||||
},
|
||||
{
|
||||
"id": "FC13",
|
||||
"repo": "lab-rv32i-freertos-c-uart",
|
||||
"branch": "main",
|
||||
"title": "UART Interrupt-to-task Pipeline"
|
||||
},
|
||||
{
|
||||
"id": "FC14",
|
||||
"repo": "lab-rv32i-freertos-c-gpio-timer",
|
||||
"branch": "main",
|
||||
"title": "GPIO, Hardware Timer and Deferred Work"
|
||||
},
|
||||
{
|
||||
"id": "FC15",
|
||||
"repo": "lab-rv32i-freertos-c-integration",
|
||||
"branch": "main",
|
||||
"title": "Integrated Deterministic FreeRTOS C Application"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -15,6 +15,90 @@
|
||||
"repo": "lab-rv32i-freertos-task-stack-vector",
|
||||
"branch": "main",
|
||||
"title": "C++ Task wrapper: OOP and lifecycle"
|
||||
},
|
||||
{
|
||||
"id": "K03",
|
||||
"repo": "lab-rv32i-freertos-vector-raii",
|
||||
"branch": "main",
|
||||
"title": "Vector V1: destructor, move, ownership and RAII"
|
||||
},
|
||||
{
|
||||
"id": "K04",
|
||||
"repo": "lab-rv32i-freertos-scheduler-states",
|
||||
"branch": "main",
|
||||
"title": "Scheduler states, priorities and typed ticks"
|
||||
},
|
||||
{
|
||||
"id": "K05",
|
||||
"repo": "lab-rv32i-freertos-heap-models",
|
||||
"branch": "main",
|
||||
"title": "C++ heap bridge, heap models and HeapStats"
|
||||
},
|
||||
{
|
||||
"id": "K06",
|
||||
"repo": "lab-rv32i-freertos-allocator-resource",
|
||||
"branch": "main",
|
||||
"title": "MemoryResource and FreeRtosAllocator<T>"
|
||||
},
|
||||
{
|
||||
"id": "K07",
|
||||
"repo": "lab-rv32i-freertos-task-wrapper",
|
||||
"branch": "main",
|
||||
"title": "TaskHandle_t, explicit start and static trampoline"
|
||||
},
|
||||
{
|
||||
"id": "K08",
|
||||
"repo": "lab-rv32i-freertos-static-task",
|
||||
"branch": "main",
|
||||
"title": "DynamicTask, StaticTask, deletion and lifetime"
|
||||
},
|
||||
{
|
||||
"id": "K09",
|
||||
"repo": "lab-rv32i-freertos-kernel-facade",
|
||||
"branch": "main",
|
||||
"title": "Scheduler facade and scoped kernel guards"
|
||||
},
|
||||
{
|
||||
"id": "K10",
|
||||
"repo": "lab-rv32i-freertos-queue",
|
||||
"branch": "main",
|
||||
"title": "Queue<T> and StaticQueue<T, N>"
|
||||
},
|
||||
{
|
||||
"id": "K11",
|
||||
"repo": "lab-rv32i-freertos-mutex",
|
||||
"branch": "main",
|
||||
"title": "Mutex, LockGuard and priority inheritance"
|
||||
},
|
||||
{
|
||||
"id": "K12",
|
||||
"repo": "lab-rv32i-freertos-semaphore-notify",
|
||||
"branch": "main",
|
||||
"title": "Semaphores and task notifications"
|
||||
},
|
||||
{
|
||||
"id": "K13",
|
||||
"repo": "lab-rv32i-freertos-event-group",
|
||||
"branch": "main",
|
||||
"title": "EventGroup and coordinated state"
|
||||
},
|
||||
{
|
||||
"id": "K14",
|
||||
"repo": "lab-rv32i-freertos-sw-timer",
|
||||
"branch": "main",
|
||||
"title": "Software timer and the timer daemon task"
|
||||
},
|
||||
{
|
||||
"id": "K15",
|
||||
"repo": "lab-rv32i-freertos-isr-drivers",
|
||||
"branch": "main",
|
||||
"title": "Explicit FromISR, UART and GPIO wrappers"
|
||||
},
|
||||
{
|
||||
"id": "K16",
|
||||
"repo": "lab-rv32i-freertos-integration",
|
||||
"branch": "main",
|
||||
"title": "Integrated real-time application and evidence"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"id": "rv32i-asm",
|
||||
"title": "ASM · RV32I From Blinker to RISC-V",
|
||||
"source_org": "edu-inf",
|
||||
"answer_org": "c2025-1a-inf",
|
||||
"source_remote": "r1",
|
||||
"answer_remote": "r1a",
|
||||
"fallback_branch": "main",
|
||||
"workspace_dir": "inf",
|
||||
"source_dir": "inf",
|
||||
"default_card": "L01",
|
||||
"cards": [
|
||||
{
|
||||
"id": "L01",
|
||||
"repo": "lab-rv32i-asm-number-systems",
|
||||
"branch": "main",
|
||||
"title": "Number Systems and Storage"
|
||||
},
|
||||
{
|
||||
"id": "L02",
|
||||
"repo": "lab-rv32i-asm-fpga-bringup",
|
||||
"branch": "main",
|
||||
"title": "FPGA Bring-up and Programming"
|
||||
},
|
||||
{
|
||||
"id": "L03",
|
||||
"repo": "lab-rv32i-asm-blinker",
|
||||
"branch": "main",
|
||||
"title": "Blinker and Synchronous Logic"
|
||||
},
|
||||
{
|
||||
"id": "L04",
|
||||
"repo": "lab-rv32i-asm-decoder",
|
||||
"branch": "main",
|
||||
"title": "The RISC-V ISA and Instruction Decoder"
|
||||
},
|
||||
{
|
||||
"id": "L05",
|
||||
"repo": "lab-rv32i-asm-alu",
|
||||
"branch": "main",
|
||||
"title": "ALU and the Verilog Assembler"
|
||||
},
|
||||
{
|
||||
"id": "L06",
|
||||
"repo": "lab-rv32i-asm-control-flow",
|
||||
"branch": "main",
|
||||
"title": "Control Flow — Jumps and Branches"
|
||||
},
|
||||
{
|
||||
"id": "L07",
|
||||
"repo": "lab-rv32i-asm-addresses-memory",
|
||||
"branch": "main",
|
||||
"title": "Addresses and Memory"
|
||||
},
|
||||
{
|
||||
"id": "L08",
|
||||
"repo": "lab-rv32i-asm-subroutines-abi",
|
||||
"branch": "main",
|
||||
"title": "Subroutines and ABI"
|
||||
},
|
||||
{
|
||||
"id": "L09",
|
||||
"repo": "lab-rv32i-asm-load-store",
|
||||
"branch": "main",
|
||||
"title": "Load and Store Semantics"
|
||||
}
|
||||
]
|
||||
}
|
||||
Executable
+675
@@ -0,0 +1,675 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate the ten C++20 cards for Year 2, semester 1.
|
||||
|
||||
The lesson scope comes from /home/user/dev/keys/cxx.md. The generated cards
|
||||
share the same runtime, React viewer and PDF contract as the existing STEM
|
||||
cards, while every task contains an independently compilable C++ experiment.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import stat
|
||||
import textwrap
|
||||
import uuid
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[3]
|
||||
OUTPUT = ROOT / "series" / "cpp"
|
||||
TEMPLATE = ROOT / "series" / "console" / "lab-console-busybox"
|
||||
UUID_NAMESPACE = uuid.UUID("1b43af4e-354f-51dc-a42a-67593c614624")
|
||||
|
||||
|
||||
def clean(text: str) -> str:
|
||||
return textwrap.dedent(text).lstrip()
|
||||
|
||||
|
||||
LESSONS = [
|
||||
{
|
||||
"id": "CPP01",
|
||||
"number": "01",
|
||||
"repo": "lab-cpp-build-namespaces",
|
||||
"slug": "build-namespaces",
|
||||
"title": "Od C do C++: oddzielna kompilacja i przestrzenie nazw",
|
||||
"topic": "Deklaracja, definicja, translation unit, linkage i namespace",
|
||||
"chapter": "A Tour of C++ 3e: rozdziały 1 i 3",
|
||||
"mission": "Zbudować program z wielu jednostek translacji i odczytać granice nazw oraz linkage.",
|
||||
"tasks": [
|
||||
("Deklaracja i definicja", "Rozdziel deklarację funkcji, definicję i punkt wejścia między trzy pliki.", "sum=7", {
|
||||
"calculator.hpp": """#pragma once
|
||||
namespace lab { int add(int left, int right); }
|
||||
""",
|
||||
"calculator.cpp": """#include "calculator.hpp"
|
||||
namespace lab { int add(int left, int right) { return left + right; } }
|
||||
""",
|
||||
"main.cpp": """#include "calculator.hpp"
|
||||
#include <iostream>
|
||||
int main() { std::cout << "sum=" << lab::add(3, 4) << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Linkage zewnętrzny i wewnętrzny", "Porównaj symbol dostępny między plikami z nazwą ukrytą w anonimowej przestrzeni nazw.", "external=5 internal_bias_result=8", {
|
||||
"api.hpp": """#pragma once
|
||||
int global_value();
|
||||
int shifted_value();
|
||||
""",
|
||||
"global.cpp": """#include "api.hpp"
|
||||
int global_value() { return 5; }
|
||||
""",
|
||||
"shifted.cpp": """#include "api.hpp"
|
||||
namespace { constexpr int bias = 3; }
|
||||
int shifted_value() { return global_value() + bias; }
|
||||
""",
|
||||
"main.cpp": """#include "api.hpp"
|
||||
#include <iostream>
|
||||
int main() { std::cout << "external=" << global_value() << " internal_bias_result=" << shifted_value() << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Kwalifikacja przestrzeni nazw", "Użyj dwóch funkcji o tej samej nazwie bez kolizji i wywołaj je kwalifikowaną nazwą.", "sensor=21 network=204", {
|
||||
"main.cpp": """#include <iostream>
|
||||
namespace sensor { int read() { return 21; } }
|
||||
namespace network { int read() { return 204; } }
|
||||
int main() { std::cout << "sensor=" << sensor::read() << " network=" << network::read() << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "CPP02", "number": "02", "repo": "lab-cpp-types-initialization", "slug": "types-initialization",
|
||||
"title": "Typy, inicjalizacja, auto, const i enum class",
|
||||
"topic": "Bezpieczna inicjalizacja i typy definiowane przez użytkownika",
|
||||
"chapter": "A Tour of C++ 3e: rozdziały 1 i 2",
|
||||
"mission": "Rozpoznać typy wyrażeń i używać inicjalizacji, const oraz enum class bez niejawnego mieszania domen.",
|
||||
"tasks": [
|
||||
("Inicjalizacja i auto", "Zastosuj inicjalizację klamrową i potwierdź typ dedukowany przez auto.", "count=4 twice=8 type=int", {
|
||||
"main.cpp": """#include <iostream>
|
||||
#include <type_traits>
|
||||
int main() {
|
||||
int count{4};
|
||||
auto twice = count * 2;
|
||||
static_assert(std::is_same_v<decltype(twice), int>);
|
||||
std::cout << "count=" << count << " twice=" << twice << " type=int\\n";
|
||||
}
|
||||
""",
|
||||
}),
|
||||
("const i constexpr", "Oddziel wartość obliczaną w czasie kompilacji od obiektu tylko do odczytu.", "square=49 limit=12", {
|
||||
"main.cpp": """#include <iostream>
|
||||
constexpr int square(int value) { return value * value; }
|
||||
int main() {
|
||||
constexpr int result = square(7);
|
||||
const int limit{12};
|
||||
static_assert(result == 49);
|
||||
std::cout << "square=" << result << " limit=" << limit << '\\n';
|
||||
}
|
||||
""",
|
||||
}),
|
||||
("enum class i struktura", "Zbuduj typ rekordu oraz silnie typowany stan bez niejawnej konwersji do int.", "sample=23 state=ready", {
|
||||
"main.cpp": """#include <iostream>
|
||||
enum class State { idle, ready };
|
||||
struct Sample { int value; State state; };
|
||||
int main() {
|
||||
Sample sample{23, State::ready};
|
||||
std::cout << "sample=" << sample.value << " state=" << (sample.state == State::ready ? "ready" : "idle") << '\\n';
|
||||
}
|
||||
""",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "CPP03", "number": "03", "repo": "lab-cpp-pointers-references", "slug": "pointers-references",
|
||||
"title": "Wskaźniki, referencje, tablice i nullptr",
|
||||
"topic": "Tożsamość obiektu, dostęp pośredni i przekazywanie argumentów",
|
||||
"chapter": "A Tour of C++ 3e: sekcje 1.7 i 3.4",
|
||||
"mission": "Odróżnić wskaźnik od referencji i tablicę od wskaźnika podczas przekazywania danych.",
|
||||
"tasks": [
|
||||
("Wskaźnik i nullptr", "Sprawdź brak obiektu przed dereferencją, a następnie zmodyfikuj wskazywaną wartość.", "null=1 value=9", {
|
||||
"main.cpp": """#include <iostream>
|
||||
int main() {
|
||||
int value{7};
|
||||
int* pointer = nullptr;
|
||||
const bool was_null = pointer == nullptr;
|
||||
pointer = &value;
|
||||
*pointer += 2;
|
||||
std::cout << "null=" << was_null << " value=" << value << '\\n';
|
||||
}
|
||||
""",
|
||||
}),
|
||||
("Referencja jako alias", "Przekaż dwa obiekty przez referencję i zamień ich wartości.", "left=8 right=3", {
|
||||
"main.cpp": """#include <iostream>
|
||||
void swap_values(int& left, int& right) { const int temp = left; left = right; right = temp; }
|
||||
int main() { int left{3}; int right{8}; swap_values(left, right); std::cout << "left=" << left << " right=" << right << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Tablica i jej rozmiar", "Policz elementy w referencji do tablicy, zanim argument zaniknie do wskaźnika.", "count=4 sum=20", {
|
||||
"main.cpp": """#include <cstddef>
|
||||
#include <iostream>
|
||||
template <std::size_t N> int sum(const int (&values)[N]) { int result{}; for (int value : values) result += value; return result; }
|
||||
int main() { int values[]{2, 4, 6, 8}; std::cout << "count=" << (sizeof(values) / sizeof(values[0])) << " sum=" << sum(values) << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "CPP04", "number": "04", "repo": "lab-cpp-functions-overloading", "slug": "functions-overloading",
|
||||
"title": "Funkcje, przeciążanie, wartości zwracane i modułowość",
|
||||
"topic": "Sygnatura funkcji, wybór przeciążenia, zakres i granica modułu",
|
||||
"chapter": "A Tour of C++ 3e: rozdziały 1 i 3",
|
||||
"mission": "Zaprojektować mały interfejs funkcji i sprawdzić wybór przeciążenia oraz zwracanie wartości.",
|
||||
"tasks": [
|
||||
("Przeciążanie", "Wywołaj dwie funkcje o tej samej nazwie i różnych typach parametrów.", "int=6 double=3.5", {
|
||||
"main.cpp": """#include <iostream>
|
||||
int twice(int value) { return value * 2; }
|
||||
double twice(double value) { return value * 2.0; }
|
||||
int main() { std::cout << "int=" << twice(3) << " double=" << twice(1.75) << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Zwracanie przez wartość", "Zwróć kompletny wynik obliczenia jako wartość, bez ujawniania obiektu lokalnego.", "quotient=3 remainder=2", {
|
||||
"main.cpp": """#include <iostream>
|
||||
struct Division { int quotient; int remainder; };
|
||||
Division divide(int value, int by) { return {value / by, value % by}; }
|
||||
int main() { const Division result = divide(17, 5); std::cout << "quotient=" << result.quotient << " remainder=" << result.remainder << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Interfejs modułu", "Oddziel publiczne deklaracje statystyk od ich implementacji.", "min=2 max=9", {
|
||||
"stats.hpp": """#pragma once
|
||||
namespace stats { int minimum(int left, int right); int maximum(int left, int right); }
|
||||
""",
|
||||
"stats.cpp": """#include "stats.hpp"
|
||||
namespace stats { int minimum(int left, int right) { return left < right ? left : right; } int maximum(int left, int right) { return left > right ? left : right; } }
|
||||
""",
|
||||
"main.cpp": """#include "stats.hpp"
|
||||
#include <iostream>
|
||||
int main() { std::cout << "min=" << stats::minimum(9, 2) << " max=" << stats::maximum(9, 2) << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "CPP05", "number": "05", "repo": "lab-cpp-classes-objects", "slug": "classes-objects",
|
||||
"title": "Klasa i obiekt: interfejs oraz implementacja",
|
||||
"topic": "Pola, metody, kontrola dostępu i zachowanie obiektu",
|
||||
"chapter": "A Tour of C++ 3e: rozdziały 2 i 5",
|
||||
"mission": "Zamknąć stan i operacje w klasie oraz oddzielić interfejs publiczny od implementacji.",
|
||||
"tasks": [
|
||||
("Klasa w dwóch plikach", "Zdefiniuj interfejs licznika w nagłówku, a metody w osobnej jednostce translacji.", "counter=3", {
|
||||
"counter.hpp": """#pragma once
|
||||
class Counter { public: explicit Counter(int start); void increment(); int value() const; private: int value_; };
|
||||
""",
|
||||
"counter.cpp": """#include "counter.hpp"
|
||||
Counter::Counter(int start) : value_{start} {}
|
||||
void Counter::increment() { ++value_; }
|
||||
int Counter::value() const { return value_; }
|
||||
""",
|
||||
"main.cpp": """#include "counter.hpp"
|
||||
#include <iostream>
|
||||
int main() { Counter counter{2}; counter.increment(); std::cout << "counter=" << counter.value() << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Stan prywatny", "Udostępnij operacje rachunku bez publicznego zapisu pola balance.", "accepted=1 rejected=1 balance=15", {
|
||||
"main.cpp": """#include <iostream>
|
||||
class Account {
|
||||
public:
|
||||
explicit Account(int balance) : balance_{balance} {}
|
||||
bool deposit(int amount) { if (amount <= 0) return false; balance_ += amount; return true; }
|
||||
int balance() const { return balance_; }
|
||||
private: int balance_;
|
||||
};
|
||||
int main() { Account account{10}; const bool accepted = account.deposit(5); const bool rejected = !account.deposit(-2); std::cout << "accepted=" << accepted << " rejected=" << rejected << " balance=" << account.balance() << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Metody opisują zachowanie", "Przenieś obliczenie pola i skalowanie do obiektu prostokąta.", "area=24 scaled=96", {
|
||||
"main.cpp": """#include <iostream>
|
||||
class Rectangle { public: Rectangle(int width, int height) : width_{width}, height_{height} {} int area() const { return width_ * height_; } void scale(int factor) { width_ *= factor; height_ *= factor; } private: int width_; int height_; };
|
||||
int main() { Rectangle rectangle{6, 4}; const int before = rectangle.area(); rectangle.scale(2); std::cout << "area=" << before << " scaled=" << rectangle.area() << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "CPP06", "number": "06", "repo": "lab-cpp-invariants", "slug": "invariants",
|
||||
"title": "Hermetyzacja, niezmienniki i odpowiedzialność klasy",
|
||||
"topic": "Poprawny stan obiektu przed i po każdej operacji publicznej",
|
||||
"chapter": "A Tour of C++ 3e: sekcja 4.3 i rozdział 5",
|
||||
"mission": "Zdefiniować niezmiennik klasy i utrzymywać go we wszystkich publicznych operacjach.",
|
||||
"tasks": [
|
||||
("Walidowana zmiana stanu", "Odrzuć temperaturę spoza przyjętego zakresu bez uszkodzenia obiektu.", "accepted=1 rejected=1 value=25", {
|
||||
"main.cpp": """#include <iostream>
|
||||
class Temperature { public: explicit Temperature(int value) : value_{value} {} bool set(int value) { if (value < -50 || value > 150) return false; value_ = value; return true; } int value() const { return value_; } private: int value_; };
|
||||
int main() { Temperature temperature{20}; const bool accepted = temperature.set(25); const bool rejected = !temperature.set(400); std::cout << "accepted=" << accepted << " rejected=" << rejected << " value=" << temperature.value() << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Pojemność kolejki", "Nie dopuść, by liczba elementów przekroczyła pojemność lub spadła poniżej zera.", "pushes=2 overflow=1 pops=2 empty=1 depth=0", {
|
||||
"main.cpp": """#include <iostream>
|
||||
class QueueDepth { public: explicit QueueDepth(int capacity) : capacity_{capacity} {} bool push() { if (depth_ == capacity_) return false; ++depth_; return true; } bool pop() { if (depth_ == 0) return false; --depth_; return true; } int depth() const { return depth_; } private: int capacity_; int depth_{}; };
|
||||
int main() { QueueDepth queue{2}; int pushes{}; pushes += queue.push(); pushes += queue.push(); const bool overflow = !queue.push(); int pops{}; pops += queue.pop(); pops += queue.pop(); const bool empty = !queue.pop(); std::cout << "pushes=" << pushes << " overflow=" << overflow << " pops=" << pops << " empty=" << empty << " depth=" << queue.depth() << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Normalizacja przedziału", "Skonstruuj przedział zawsze spełniający start <= end.", "start=3 end=10 width=7", {
|
||||
"main.cpp": """#include <iostream>
|
||||
class Interval { public: Interval(int first, int second) : start_{first < second ? first : second}, end_{first < second ? second : first} {} int start() const { return start_; } int end() const { return end_; } int width() const { return end_ - start_; } private: int start_; int end_; };
|
||||
int main() { Interval interval{10, 3}; std::cout << "start=" << interval.start() << " end=" << interval.end() << " width=" << interval.width() << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "CPP07", "number": "07", "repo": "lab-cpp-construction-destruction", "slug": "construction-destruction",
|
||||
"title": "Konstruktory, destruktory i inicjalizacja obiektu",
|
||||
"topic": "Kolejność inicjalizacji, delegowanie konstruktorów i porządek destrukcji",
|
||||
"chapter": "A Tour of C++ 3e: rozdziały 5 i 6",
|
||||
"mission": "Zaobserwować pełny cykl tworzenia i niszczenia obiektu oraz kolejność jego części.",
|
||||
"tasks": [
|
||||
("Kolejność konstrukcji", "Zaobserwuj, że pole jest konstruowane przed ciałem konstruktora obiektu.", "member\nobject\nready", {
|
||||
"main.cpp": """#include <iostream>
|
||||
struct Member { Member() { std::cout << "member\\n"; } };
|
||||
struct Object { Member member; Object() { std::cout << "object\\n"; } };
|
||||
int main() { Object object; (void)object; std::cout << "ready\\n"; }
|
||||
""",
|
||||
}),
|
||||
("Destrukcja w odwrotnej kolejności", "Utwórz dwa obiekty automatyczne i sprawdź kolejność destruktorów.", "enter\nconstruct=A\nconstruct=B\ndestroy=B\ndestroy=A\nleave", {
|
||||
"main.cpp": """#include <iostream>
|
||||
struct Trace { const char* name; explicit Trace(const char* value) : name{value} { std::cout << "construct=" << name << '\\n'; } ~Trace() { std::cout << "destroy=" << name << '\\n'; } };
|
||||
void scope() { Trace first{"A"}; Trace second{"B"}; }
|
||||
int main() { std::cout << "enter\\n"; scope(); std::cout << "leave\\n"; }
|
||||
""",
|
||||
}),
|
||||
("Konstruktor delegujący", "Skieruj konstruktor domyślny do jednego konstruktora utrzymującego reguły inicjalizacji.", "point=0,0 other=3,4", {
|
||||
"main.cpp": """#include <iostream>
|
||||
class Point { public: Point() : Point{0, 0} {} Point(int x, int y) : x_{x}, y_{y} {} int x() const { return x_; } int y() const { return y_; } private: int x_; int y_; };
|
||||
int main() { Point point; Point other{3, 4}; std::cout << "point=" << point.x() << ',' << point.y() << " other=" << other.x() << ',' << other.y() << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "CPP08", "number": "08", "repo": "lab-cpp-scope-lifetime", "slug": "scope-lifetime",
|
||||
"title": "Zakres i czas życia obiektów",
|
||||
"topic": "Obiekty automatyczne, statyczne i dynamiczne oraz przesłanianie nazw",
|
||||
"chapter": "A Tour of C++ 3e: sekcja 1.5 i rozdział 6",
|
||||
"mission": "Powiązać miejsce przechowywania obiektu z początkiem i końcem jego czasu życia.",
|
||||
"tasks": [
|
||||
("Automatyczny i statyczny", "Porównaj nowy obiekt automatyczny z zachowującym stan obiektem statycznym.", "auto=7 static_calls=1,2", {
|
||||
"main.cpp": """#include <iostream>
|
||||
int next_call() { static int calls{}; return ++calls; }
|
||||
int main() { int automatic{7}; const int first = next_call(); const int second = next_call(); std::cout << "auto=" << automatic << " static_calls=" << first << ',' << second << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Obiekt dynamiczny", "Jawnie zestaw new z delete i obserwuj moment wykonania destruktora.", "construct\nvalue=11\ndestroy", {
|
||||
"main.cpp": """#include <iostream>
|
||||
struct Dynamic { explicit Dynamic(int value) : value{value} { std::cout << "construct\\n"; } ~Dynamic() { std::cout << "destroy\\n"; } int value; };
|
||||
int main() { Dynamic* object = new Dynamic{11}; std::cout << "value=" << object->value << '\\n'; delete object; }
|
||||
""",
|
||||
}),
|
||||
("Zakres i przesłanianie", "Pokaż, że nazwa wewnętrzna nie zmienia obiektu o tej samej nazwie w zakresie zewnętrznym.", "outer=7\ninner=9\nouter=7", {
|
||||
"main.cpp": """#include <iostream>
|
||||
int main() { int value{7}; std::cout << "outer=" << value << '\\n'; { int value{9}; std::cout << "inner=" << value << '\\n'; } std::cout << "outer=" << value << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "CPP09", "number": "09", "repo": "lab-cpp-raii", "slug": "raii",
|
||||
"title": "RAII: zasób związany z czasem życia obiektu",
|
||||
"topic": "Pozyskanie w konstruktorze, zwolnienie w destruktorze i wszystkie wyjścia z zakresu",
|
||||
"chapter": "A Tour of C++ 3e: sekcja 6.3",
|
||||
"mission": "Zapewnić zwolnienie zasobu przez strukturę programu, także przy wczesnym return.",
|
||||
"tasks": [
|
||||
("Uchwyt jako obiekt", "Zwiąż stan otwarcia uchwytu z konstruktorem i destruktorem.", "acquire\nopen=1\nrelease\nopen=0", {
|
||||
"main.cpp": """#include <iostream>
|
||||
bool resource_open{};
|
||||
class Handle { public: Handle() { resource_open = true; std::cout << "acquire\\n"; } ~Handle() { resource_open = false; std::cout << "release\\n"; } Handle(const Handle&) = delete; Handle& operator=(const Handle&) = delete; };
|
||||
int main() { { Handle handle; (void)handle; std::cout << "open=" << resource_open << '\\n'; } std::cout << "open=" << resource_open << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Wczesny return", "Potwierdź zwolnienie strażnika przy wyjściu z funkcji przed jej końcem.", "acquire\nwork=short\nrelease\nafter", {
|
||||
"main.cpp": """#include <iostream>
|
||||
struct Guard { Guard() { std::cout << "acquire\\n"; } ~Guard() { std::cout << "release\\n"; } };
|
||||
void work(bool short_path) { Guard guard; if (short_path) { std::cout << "work=short\\n"; return; } std::cout << "work=long\\n"; }
|
||||
int main() { work(true); std::cout << "after\\n"; }
|
||||
""",
|
||||
}),
|
||||
("Zagnieżdżone zasoby", "Sprawdź zwalnianie zagnieżdżonych zasobów w odwrotnej kolejności.", "acquire=A\nacquire=B\ninside\nrelease=B\nrelease=A", {
|
||||
"main.cpp": """#include <iostream>
|
||||
struct Resource { const char* name; explicit Resource(const char* value) : name{value} { std::cout << "acquire=" << name << '\\n'; } ~Resource() { std::cout << "release=" << name << '\\n'; } };
|
||||
int main() { Resource first{"A"}; { Resource second{"B"}; std::cout << "inside\\n"; } }
|
||||
""",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "CPP10", "number": "10", "repo": "lab-cpp-copy-move", "slug": "copy-move",
|
||||
"title": "Kopiowanie, przenoszenie i Rule of Zero/Five",
|
||||
"topic": "Głębokie kopiowanie, transfer własności i typy składowe zarządzające zasobem",
|
||||
"chapter": "A Tour of C++ 3e: sekcje 6.2–6.4",
|
||||
"mission": "Rozróżnić kopię od przeniesienia i wybrać Rule of Zero dla bezpiecznego typu zasobowego.",
|
||||
"tasks": [
|
||||
("Głęboka kopia", "Zaimplementuj kopię bufora tak, aby dwa obiekty nie współdzieliły jednej komórki.", "original=7 copy=9 distinct=1", {
|
||||
"main.cpp": """#include <iostream>
|
||||
class Buffer { public: explicit Buffer(int value) : data_{new int{value}} {} ~Buffer() { delete data_; } Buffer(const Buffer& other) : data_{new int{*other.data_}} {} Buffer& operator=(const Buffer&) = delete; int value() const { return *data_; } void set(int value) { *data_ = value; } const int* address() const { return data_; } private: int* data_; };
|
||||
int main() { Buffer original{7}; Buffer copy{original}; copy.set(9); std::cout << "original=" << original.value() << " copy=" << copy.value() << " distinct=" << (original.address() != copy.address()) << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Przeniesienie własności", "Przenieś bufor move-only i pozostaw obiekt źródłowy w poprawnym stanie pustym.", "src_empty=1 value=42", {
|
||||
"main.cpp": """#include <iostream>
|
||||
#include <utility>
|
||||
class Buffer { public: explicit Buffer(int value) : data_{new int{value}} {} ~Buffer() { delete data_; } Buffer(const Buffer&) = delete; Buffer& operator=(const Buffer&) = delete; Buffer(Buffer&& other) noexcept : data_{std::exchange(other.data_, nullptr)} {} bool empty() const { return data_ == nullptr; } int value() const { return *data_; } private: int* data_; };
|
||||
int main() { Buffer source{42}; Buffer target{std::move(source)}; std::cout << "src_empty=" << source.empty() << " value=" << target.value() << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
("Rule of Zero", "Zbuduj typ z bezpiecznych składowych standardowych bez własnego destruktora i operacji copy/move.", "copy=alpha original=beta moved=alpha", {
|
||||
"main.cpp": """#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
struct Document { std::string text; };
|
||||
int main() { Document original{"alpha"}; Document copy = original; original.text = "beta"; Document moved = std::move(copy); std::cout << "copy=" << moved.text << " original=" << original.text << " moved=" << moved.text << '\\n'; }
|
||||
""",
|
||||
}),
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
CARD_ACTION = r'''#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
action="${1:?action is required}"
|
||||
root="${STEM_REPO:-${CARD_ROOT:-$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)}}"
|
||||
profile="${STEM_PROFILE:-native-amd64}"
|
||||
target="${STEM_TARGET:-native}"
|
||||
selector="${STEM_TASK:-task1}"
|
||||
card_id="$(sed -n 's/^card: cpp\///p' "$root/lesson-flow.yaml" | head -n1)"
|
||||
resolve_task() {
|
||||
local value="${1,,}"
|
||||
if [[ "$value" =~ ^(task|t)?[-_]?0*([1-3])($|[-_].*) ]]; then printf 'task%02d\n' "${BASH_REMATCH[2]}"; return; fi
|
||||
[[ "$value" =~ ^task0[1-3]$ ]] && { printf '%s\n' "$value"; return; }
|
||||
printf 'Unknown task selector: %s\n' "$1" >&2; exit 2
|
||||
}
|
||||
task="$(resolve_task "$selector")"
|
||||
artifact_dir="$root/.stem/artifacts/$profile/$target/$task"
|
||||
binary="$artifact_dir/program"
|
||||
mkdir -p "$artifact_dir"
|
||||
compile_task() {
|
||||
local selected="$1" output="$2"
|
||||
mapfile -t sources < <(find "$root/src/$selected" -maxdepth 1 -type f -name '*.cpp' | sort)
|
||||
[[ ${#sources[@]} -gt 0 ]] || { printf 'No C++ sources for %s\n' "$selected" >&2; exit 2; }
|
||||
"${CXX:-g++}" -std=c++20 -Wall -Wextra -Wpedantic -Werror -O0 -g3 -fno-omit-frame-pointer -I"$root/src/$selected" "${sources[@]}" -o "$output"
|
||||
}
|
||||
verify_task() {
|
||||
local selected="$1" output="$2" actual="$artifact_dir/actual.txt"
|
||||
compile_task "$selected" "$output"
|
||||
"$output" >"$actual"
|
||||
diff -u "$root/tests/expected/$selected.txt" "$actual"
|
||||
}
|
||||
case "$profile:$target:$action" in
|
||||
native-amd64:native:build)
|
||||
for item in task01 task02 task03; do
|
||||
current="$root/.stem/artifacts/$profile/$target/$item"
|
||||
mkdir -p "$current"
|
||||
compile_task "$item" "$current/program"
|
||||
done
|
||||
printf 'BUILD %s standard=c++20 tasks=3\n' "$card_id"
|
||||
;;
|
||||
native-amd64:native:test|native-amd64:native:run)
|
||||
verify_task "$task" "$binary"
|
||||
printf 'PASS %s %s standard=c++20\n' "$card_id" "$task"
|
||||
;;
|
||||
native-amd64:native:debug)
|
||||
verify_task "$task" "$binary"
|
||||
trace="$artifact_dir/debug.log"
|
||||
if command -v gdb >/dev/null 2>&1; then
|
||||
gdb -q -batch -ex 'set pagination off' -ex 'set debuginfod enabled off' -ex 'break main' -ex run -ex 'info source' -ex 'info args' -ex continue "$binary" >"$trace" 2>&1
|
||||
else
|
||||
{ printf 'gdb unavailable; binary evidence follows\n'; "${NM:-nm}" -C "$binary" | head -n 80; "$binary"; } >"$trace" 2>&1
|
||||
fi
|
||||
cat "$trace"
|
||||
[[ -s "$trace" ]]
|
||||
printf 'TRACE %s %s log=%s\n' "$card_id" "$task" "$trace"
|
||||
;;
|
||||
*) printf 'Unsupported profile/target/action: %s/%s/%s\n' "$profile" "$target" "$action" >&2; exit 2 ;;
|
||||
esac
|
||||
'''
|
||||
|
||||
|
||||
def write(path: Path, content: str, executable: bool = False) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(clean(content), encoding="utf-8")
|
||||
if executable:
|
||||
path.chmod(path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||
|
||||
|
||||
def card_source(lesson: dict, document_uuid: str) -> dict:
|
||||
prefix = lesson["id"]
|
||||
sections = []
|
||||
tasks = {}
|
||||
scope_rows = []
|
||||
for index, (title, prompt, expected, _files) in enumerate(lesson["tasks"], 1):
|
||||
task_id = f"task{index:02d}"
|
||||
expected_tex = expected.replace("_", "\\_")
|
||||
sections.append({
|
||||
"title": f"Task{index:02d} · {title}",
|
||||
"content_kind": "prose",
|
||||
"content_tex": f"{prompt} Najpierw przewidź wynik, następnie skompiluj program z ostrzeżeniami traktowanymi jako błędy i porównaj dokładny stdout z kontraktem: {expected_tex.replace(chr(10), '; ')}.",
|
||||
"educational_requirement_refs": [f"{prefix}.WE01"],
|
||||
"learning_effect_refs": [f"{prefix}.EN01", f"{prefix}.EK01"],
|
||||
"assessment_criterion_refs": [f"{prefix}.KW01"],
|
||||
"area_tree_refs": [f"{prefix}.WE01.OG.IP.01", f"{prefix}.WE01.TECH.I4.01"],
|
||||
"steps": [
|
||||
{"id": f"T{index:02d}-PREDICT", "title": "Zapisz przewidywany wynik i wskaż regułę języka.", "tree_refs": [f"{prefix}.WE01.OG.IP.01"]},
|
||||
{"id": f"T{index:02d}-VERIFY", "title": "Uruchom test i zachowaj mierzalny dowód wykonania.", "tree_refs": [f"{prefix}.WE01.TECH.I4.01"]},
|
||||
],
|
||||
})
|
||||
tasks[task_id] = {
|
||||
"prompt_tex": prompt,
|
||||
"criterion": expected_tex.replace("\n", "; "),
|
||||
"assessment_criterion_ref": f"{prefix}.KW01",
|
||||
}
|
||||
scope_rows.append({"chapter": "1", "task": f"Task{index:02d}", "idea_tex": title, "priority": "obowiązkowe", "status": "ready", "version": "v00.01"})
|
||||
|
||||
return {
|
||||
"$schema": "../../../../tools/card-layouts/schemas/card-source.schema.json",
|
||||
"schema": "esc-card-source.v1",
|
||||
"card": {
|
||||
"id": f"mpabi-inf-cpp-y2s1-{lesson['number']}-{lesson['slug']}",
|
||||
"series": "cpp",
|
||||
"series_title": "C++ · Rok 2 · Semestr 1",
|
||||
"number": lesson["number"], "count": "10", "slug": lesson["slug"],
|
||||
"title": f"{lesson['id']} · {lesson['title']}", "topic": lesson["topic"],
|
||||
"project": "C++20 · fundamenty języka i modelu obiektu", "subject": "Informatyka",
|
||||
"level": "Rok 2 · Semestr 1", "revision_date": "2026-07-21T00:00:00+02:00",
|
||||
"status": "Gotowa do wykonania", "version": "v00.01", "uuid": document_uuid,
|
||||
"author": "M. Pabiszczak", "year": "2026",
|
||||
},
|
||||
"generated": {"tex": "doc/generated/main.tex", "html": "web/index.html", "html_css": "web/style.css", "react_app": True, "html_tree_inspector": False},
|
||||
"template": "templates/karta-klasyczna.json",
|
||||
"title_block": {
|
||||
"category": "KARTA PRACY · INFORMATYKA · C++20", "standard": "ISO 7200",
|
||||
"prepared_by": "M. Pabiszczak", "prepared_on": "21.07.2026", "checked_by": "testy automatyczne", "approved_by": "—",
|
||||
"url": "http://localhost:8080", "repository_url": f"https://zsl-gitea.mpabi.pl/edu-cpp/{lesson['repo']}",
|
||||
"revision": "1", "issued_on": "21.07.2026", "series": f"CPP-Y2S1-{lesson['number']}", "document_type": "karta pracy",
|
||||
"tool": "card-layouts", "sheet": "1 / 1", "show_qr": False, "show_repository_qr": False,
|
||||
"height_cm": 3, "repeat_on_every_page": True, "replace_front_matter": True,
|
||||
},
|
||||
"front_page_scope": {"title": "Cel karty", "content_tex": lesson["mission"], "scope_title": "Zakres tasków", "scope_table": {"headers": ["Krok", "Numer tasku", "Najważniejsza idea", "Priorytet", "Status", "Version"], "rows": scope_rows}},
|
||||
"learning_effects": {
|
||||
f"{prefix}.EN01": {"text": f"Uczeń wyjaśnia reguły C++20 związane z tematem: {lesson['topic']}.", "label": "Model języka", "bloom_level": "Analiza", "assessment_criteria": [f"{prefix}.KW01"]},
|
||||
f"{prefix}.EK01": {"text": "Uczeń implementuje, kompiluje i weryfikuje trzy małe eksperymenty C++20.", "label": "Eksperyment C++", "bloom_level": "Zastosowanie", "assessment_criteria": [f"{prefix}.KW01"]},
|
||||
},
|
||||
"assessment_criteria": {f"{prefix}.KW01": {"text": "Trzy taski kompilują się bez ostrzeżeń i zwracają dokładny, testowany wynik.", "learning_effects": [f"{prefix}.EN01", f"{prefix}.EK01"]}},
|
||||
"educational_requirements": {
|
||||
f"{prefix}.WE01": {"text": lesson["mission"], "label": lesson["topic"], "learning_effects": [f"{prefix}.EN01", f"{prefix}.EK01"],
|
||||
"learning_tree": {"schema": "we-learning-tree.v1", "policy": "Każde twierdzenie o języku ma dowód w kodzie, wyniku programu albo symbolach binarnych.",
|
||||
"ogolne": [{"tree_id": f"{prefix}.WE01.OG.IP.01", "effect_ref": f"{prefix}.EN01", "display": f"EN IP {prefix}", "text": "Uczeń przewiduje zachowanie programu na podstawie reguł języka.", "kw": [{"criterion_ref": f"{prefix}.KW01", "display": f"KW IP {prefix}", "text": "Uzasadnia przewidywany wynik."}]}],
|
||||
"zawodowe": [{"tree_id": f"{prefix}.WE01.TECH.I4.01", "effect_ref": f"{prefix}.EK01", "display": f"EK INF04 {prefix}", "text": "Uczeń buduje i testuje program C++20.", "kw": [{"criterion_ref": f"{prefix}.KW01", "display": f"KW INF04 {prefix}", "text": "Uzyskuje trzy komunikaty PASS."}]}],
|
||||
},
|
||||
}
|
||||
},
|
||||
"sections": sections, "tasks": tasks, "tasks_order": ["task01", "task02", "task03"],
|
||||
"mission": lesson["mission"],
|
||||
"objectives": ["Wyjaśnisz badaną regułę C++20.", "Skompilujesz program z pełnym zestawem ostrzeżeń.", "Porównasz dokładny wynik i ślad debuggera."],
|
||||
"agenda": [{"time": "0--15 min", "work": "Model i przewidywanie."}, {"time": "15--45 min", "work": "Trzy eksperymenty kodowe."}, {"time": "45--60 min", "work": "Debug, wnioski i raport."}],
|
||||
"tech_stack": {"software": [{"name": "C++20", "use": "standard języka"}, {"name": "GCC/GDB", "use": "kompilacja i dowód wykonania"}, {"name": "stemctl", "use": "izolowany profil native-amd64"}], "hardware": [{"name": "Brak", "use": "laboratorium kontenerowe"}]},
|
||||
"container_test": {"title": "Test w profilu native-amd64", "commands": [f"stemctl test native-amd64 cpp {lesson['id']} 1", f"stemctl test native-amd64 cpp {lesson['id']} 2", f"stemctl debug native-amd64 cpp {lesson['id']} 3"], "pass_condition": "Trzy wyniki zgodne z expected i niepusty debug.log."},
|
||||
"safety_rules": [{"title": "Brak niezdefiniowanego zachowania", "body": "Kod testowy nie dereferencjonuje nullptr i nie używa obiektu po zakończeniu czasu życia."}, {"title": "Jedna zmienna naraz", "body": "Każdy task izoluje jedną regułę języka i ma deterministyczny stdout."}],
|
||||
"hardware_procedure": [{"step": "1", "action": "Przewidź wynik.", "condition": "Reguła języka zapisana przed uruchomieniem."}, {"step": "2", "action": "Uruchom trzy taski.", "condition": "Trzy komunikaty PASS."}, {"step": "3", "action": "Odczytaj debug.log.", "condition": "Debugger zatrzymał program w main."}],
|
||||
"references": [],
|
||||
}
|
||||
|
||||
|
||||
def generate_lesson(lesson: dict) -> None:
|
||||
repo = OUTPUT / lesson["repo"]
|
||||
if repo.exists() and (repo / ".git").exists():
|
||||
raise SystemExit(f"Refusing to overwrite Git repository: {repo}")
|
||||
if repo.exists():
|
||||
shutil.rmtree(repo)
|
||||
repo.mkdir(parents=True)
|
||||
|
||||
shutil.copytree(TEMPLATE / "scripts", repo / "scripts")
|
||||
shutil.copy2(TEMPLATE / ".gitignore", repo / ".gitignore")
|
||||
(repo / "web").mkdir(parents=True)
|
||||
shutil.copy2(TEMPLATE / "web" / "app.css", repo / "web" / "app.css")
|
||||
(repo / "doc" / "pdf").mkdir(parents=True)
|
||||
write(repo / "doc" / "pdf" / ".gitkeep", "")
|
||||
|
||||
package = json.loads((TEMPLATE / "package.json").read_text(encoding="utf-8"))
|
||||
package["name"] = f"mpabi-inf-cpp-y2s1-{lesson['number']}-{lesson['slug']}"
|
||||
write(repo / "package.json", json.dumps(package, ensure_ascii=False, indent=2) + "\n")
|
||||
lock = json.loads((TEMPLATE / "package-lock.json").read_text(encoding="utf-8"))
|
||||
lock["name"] = package["name"]
|
||||
if "packages" in lock and "" in lock["packages"]:
|
||||
lock["packages"][""]["name"] = package["name"]
|
||||
write(repo / "package-lock.json", json.dumps(lock, ensure_ascii=False, indent=2) + "\n")
|
||||
|
||||
write(repo / "stem-card.yaml", """
|
||||
schema: 1
|
||||
targets:
|
||||
native: {profile: native-amd64, actions: [build, test, run, debug]}
|
||||
actions:
|
||||
build: [bash, tools/card-action.sh, build]
|
||||
test: [bash, tools/card-action.sh, test]
|
||||
run: [bash, tools/card-action.sh, run]
|
||||
debug: [bash, tools/card-action.sh, debug]
|
||||
artifacts: {directory: .stem/artifacts}
|
||||
""")
|
||||
write(repo / "tools" / "card-action.sh", CARD_ACTION, executable=True)
|
||||
write(repo / "Makefile", """
|
||||
TASK ?= task01
|
||||
.PHONY: build test run trace clean
|
||||
build:
|
||||
\t@CARD_ROOT="$(CURDIR)" tools/card-action.sh build
|
||||
test:
|
||||
\t@CARD_ROOT="$(CURDIR)" STEM_TASK="$(TASK)" tools/card-action.sh test
|
||||
run: test
|
||||
trace:
|
||||
\t@CARD_ROOT="$(CURDIR)" STEM_TASK="$(TASK)" tools/card-action.sh debug
|
||||
clean:
|
||||
\t@find .stem/artifacts -mindepth 1 -maxdepth 7 -type f -delete 2>/dev/null || true
|
||||
""")
|
||||
|
||||
flow = ["schema: 1", f"card: cpp/{lesson['id']}", f"title: {lesson['title']}", "steps:"]
|
||||
for index, (title, _prompt, _expected, _files) in enumerate(lesson["tasks"], 1):
|
||||
flow.extend([
|
||||
f" - id: task-{index:02d}", f" task: task{index:02d}", " action: test", " profile: native-amd64", " target: native",
|
||||
f" command: stemctl test native-amd64 cpp {lesson['id']} {index}",
|
||||
f" board:", f" show: [source, stdout, binary]", f" highlight: [cxx20, {lesson['slug'].replace('-', '_')}]",
|
||||
f" question: {title} — jaka reguła języka wyjaśnia dokładny wynik?",
|
||||
f" evidence: [compile_warnings_zero, expected_stdout, exit_zero]",
|
||||
])
|
||||
write(repo / "lesson-flow.yaml", "\n".join(flow) + "\n")
|
||||
|
||||
for index, (_title, _prompt, expected, files) in enumerate(lesson["tasks"], 1):
|
||||
task = f"task{index:02d}"
|
||||
for name, source in files.items():
|
||||
write(repo / "src" / task / name, source)
|
||||
write(repo / "tests" / "expected" / f"{task}.txt", expected + "\n")
|
||||
|
||||
document_uuid = str(uuid.uuid5(UUID_NAMESPACE, lesson["repo"]))
|
||||
source = card_source(lesson, document_uuid)
|
||||
write(repo / "json" / "card_source.json", json.dumps(source, ensure_ascii=False, indent=2) + "\n")
|
||||
write(repo / "doc" / "main.tex", f"""
|
||||
\\newcommand{{\\PublisherDomain}}{{mpabi}}
|
||||
\\newcommand{{\\CardArea}}{{inf}}
|
||||
\\newcommand{{\\CardSeries}}{{cpp-y2s1}}
|
||||
\\newcommand{{\\CardNumber}}{{{lesson['number']}}}
|
||||
\\newcommand{{\\CardSlug}}{{{lesson['slug']}}}
|
||||
\\newcommand{{\\CardVersion}}{{v00.01}}
|
||||
\\newcommand{{\\DocumentUUID}}{{{document_uuid}}}
|
||||
""")
|
||||
|
||||
expected_rows = "\n".join(f"| Task{index:02d} | `{title}` | `{expected.replace(chr(10), ' / ')}` |" for index, (title, _prompt, expected, _files) in enumerate(lesson["tasks"], 1))
|
||||
write(repo / "README.md", f"""
|
||||
# {lesson['id']} — {lesson['title']}
|
||||
|
||||
Karta {lesson['number']}/10 kursu **C++ · Rok 2 · Semestr 1**. Standard: C++20.
|
||||
Oś merytoryczna: {lesson['chapter']}. Materiał książkowy jest parafrazowany;
|
||||
repozytorium zawiera samodzielne eksperymenty i testy, a nie kopię książki.
|
||||
|
||||
## Taski
|
||||
|
||||
| Task | Temat | Dokładny dowód stdout |
|
||||
| --- | --- | --- |
|
||||
{expected_rows}
|
||||
|
||||
Każdy task jest osobnym programem w `src/task0N`. Test kompiluje wszystkie
|
||||
jednostki translacji poleceniem zgodnym z `-std=c++20 -Wall -Wextra
|
||||
-Wpedantic -Werror`, uruchamia program i porównuje dokładny wynik.
|
||||
|
||||
## Uruchomienie
|
||||
|
||||
```bash
|
||||
stemctl build native-amd64 cpp {lesson['id']} 1
|
||||
stemctl test native-amd64 cpp {lesson['id']} 1
|
||||
stemctl test native-amd64 cpp {lesson['id']} 2
|
||||
stemctl debug native-amd64 cpp {lesson['id']} 3
|
||||
```
|
||||
|
||||
Lokalnie można użyć `make build`, `make test TASK=task02` i
|
||||
`make trace TASK=task03`. Ślad debuggera trafia do `.stem/artifacts`.
|
||||
|
||||
## Granica semestru
|
||||
|
||||
Ta seria nie uczy API RTOS, zaawansowanych kontenerów STL ani
|
||||
współbieżności. Są to osobne bloki następnych semestrów opisanych w
|
||||
`/home/user/dev/keys/cxx.md`.
|
||||
""")
|
||||
|
||||
answer_lines = [f"# Odpowiedzi — {lesson['id']}", "", lesson["mission"], ""]
|
||||
for index, (title, prompt, expected, files) in enumerate(lesson["tasks"], 1):
|
||||
answer_lines.extend([
|
||||
f"## Task{index:02d} — {title}", "", prompt, "",
|
||||
f"Oczekiwany stdout: `{expected.replace(chr(10), ' / ')}`.", "",
|
||||
f"Pliki dowodu: {', '.join(f'`src/task{index:02d}/{name}`' for name in sorted(files))}.", "",
|
||||
"Wynik nie jest oceniany wzrokowo: test kompiluje kod bez ostrzeżeń, uruchamia go i wykonuje dokładne `diff` z plikiem `tests/expected`.", "",
|
||||
])
|
||||
write(repo / "answers" / "solutions.md", "\n".join(answer_lines))
|
||||
|
||||
write(repo / "tests" / "card_contract.test.mjs", f"""
|
||||
import assert from 'node:assert/strict';
|
||||
import {{ access, readFile }} from 'node:fs/promises';
|
||||
import test from 'node:test';
|
||||
const source = JSON.parse(await readFile(new URL('../json/card_source.json', import.meta.url), 'utf8'));
|
||||
test('{lesson['id']} identity and task order are stable', () => {{
|
||||
assert.equal(source.card.number, '{lesson['number']}');
|
||||
assert.equal(source.card.uuid, '{document_uuid}');
|
||||
assert.deepEqual(source.tasks_order, ['task01', 'task02', 'task03']);
|
||||
assert.match(JSON.stringify(source), /C\\+\\+20/);
|
||||
}});
|
||||
test('all task programs and expected outputs exist', async () => {{
|
||||
for (const task of ['task01', 'task02', 'task03']) {{
|
||||
await access(new URL(`../src/${{task}}/main.cpp`, import.meta.url));
|
||||
await access(new URL(`./expected/${{task}}.txt`, import.meta.url));
|
||||
}}
|
||||
}});
|
||||
""")
|
||||
shutil.copy2(TEMPLATE / "tests" / "card_state_db.test.mjs", repo / "tests" / "card_state_db.test.mjs")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
OUTPUT.mkdir(parents=True, exist_ok=True)
|
||||
for lesson in LESSONS:
|
||||
generate_lesson(lesson)
|
||||
print(f"generated {lesson['id']} {lesson['repo']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+19
-1
@@ -13,7 +13,7 @@
|
||||
"title": "Legacy Informatyka series",
|
||||
"role": "series",
|
||||
"legacy": true,
|
||||
"series": ["inf", "freertos"]
|
||||
"series": ["console-bash", "inf", "rv32i-asm", "freertos"]
|
||||
},
|
||||
{
|
||||
"id": "edu-fiz",
|
||||
@@ -32,13 +32,27 @@
|
||||
"title": "FreeRTOS C++ series",
|
||||
"role": "series",
|
||||
"series": ["freertos-cpp"]
|
||||
},
|
||||
{
|
||||
"id": "edu-cpp",
|
||||
"title": "C++ course series",
|
||||
"role": "series",
|
||||
"series": ["cpp"]
|
||||
}
|
||||
],
|
||||
"series": [
|
||||
{
|
||||
"id": "console-bash",
|
||||
"file": "series/console-bash.json"
|
||||
},
|
||||
{
|
||||
"id": "inf",
|
||||
"file": "series/inf.json"
|
||||
},
|
||||
{
|
||||
"id": "rv32i-asm",
|
||||
"file": "series/rv32i-asm.json"
|
||||
},
|
||||
{
|
||||
"id": "fiz",
|
||||
"file": "series/fiz.json"
|
||||
@@ -54,6 +68,10 @@
|
||||
{
|
||||
"id": "freertos-cpp",
|
||||
"file": "series/freertos-cpp.json"
|
||||
},
|
||||
{
|
||||
"id": "cpp",
|
||||
"file": "series/cpp.json"
|
||||
}
|
||||
],
|
||||
"catalog_subjects": [
|
||||
|
||||
Reference in New Issue
Block a user