call builtin; release builder; documentation from docs repo
This commit is contained in:
parent
ddf9cc8f8c
commit
2f101fdccf
2
.gitignore
vendored
2
.gitignore
vendored
@ -8,3 +8,5 @@ doc/source/api
|
|||||||
__pycache__
|
__pycache__
|
||||||
drafts.cc
|
drafts.cc
|
||||||
.cache
|
.cache
|
||||||
|
release_*
|
||||||
|
*.zip
|
||||||
|
7
Makefile
7
Makefile
@ -37,6 +37,11 @@ doc-open: doc
|
|||||||
clean:
|
clean:
|
||||||
rm -rf bin coverage
|
rm -rf bin coverage
|
||||||
|
|
||||||
.PHONY: clean doc doc-open all test unit-tests
|
release: bin/musique
|
||||||
|
scripts/release
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: clean doc doc-open all test unit-tests release
|
||||||
|
|
||||||
$(shell mkdir -p bin/debug/tests)
|
$(shell mkdir -p bin/debug/tests)
|
||||||
|
@ -68,7 +68,7 @@ $ make bin/musique
|
|||||||
Skopiuj plik [etc/editor/musique.vim](etc/editor/musique.vim) do folderu `syntax` wewnątrz twojej konfiguracji Vima (Neovima). Np:
|
Skopiuj plik [etc/editor/musique.vim](etc/editor/musique.vim) do folderu `syntax` wewnątrz twojej konfiguracji Vima (Neovima). Np:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ cp etc/editor/musique.vim ~/.config/nvim/syntax/
|
$ cp editor/musique.vim ~/.config/nvim/syntax/
|
||||||
```
|
```
|
||||||
|
|
||||||
Następnie musisz dodać ustawienie typu pliku na podstawie rozszerzenia wewnątrz twojej konfiguracji:
|
Następnie musisz dodać ustawienie typu pliku na podstawie rozszerzenia wewnątrz twojej konfiguracji:
|
||||||
|
@ -1,119 +0,0 @@
|
|||||||
---------------------------------------------------------------------------
|
|
||||||
Składnia
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Zapis nut (dostępna notacja zachodnia)
|
|
||||||
c
|
|
||||||
d
|
|
||||||
|
|
||||||
Ustawianie oktawy
|
|
||||||
c 8
|
|
||||||
|
|
||||||
Ustawianie oktawy i długości
|
|
||||||
c 8 (1/4) c w oktawie 8 grane przez 1/4 długości pełnej nuty
|
|
||||||
|
|
||||||
Ustawianie oktawy i długości, a następnie modyfikacja
|
|
||||||
(c 8 fn) 4 zmienia oktawę na 4
|
|
||||||
(c 8 fn) 4 qn zmienia oktawę na 4 i długość na 1/4
|
|
||||||
|
|
||||||
Stworzenie akordu
|
|
||||||
c123 == chord[c; c#; d; d#]
|
|
||||||
|
|
||||||
Nutę możemy modifikować poprzez podwyższanie o półton (# lub s), lub obniżanie o półton (b lub f)
|
|
||||||
c## == css == d == dff == dbb
|
|
||||||
|
|
||||||
Arytmetyka
|
|
||||||
(aktualnie brak wsparcia dla precedensji operatorów)
|
|
||||||
3 * (4 * 12 - 8)
|
|
||||||
|
|
||||||
Przesuwanie dźwięków o półtony
|
|
||||||
c + 1 == c#
|
|
||||||
c - 1 == b
|
|
||||||
c12 + 1 == c#12
|
|
||||||
|
|
||||||
Wywołanie funkcji
|
|
||||||
foo 1 2 3
|
|
||||||
|
|
||||||
Kilka wywołań obok siebie
|
|
||||||
foo 1; bar 2
|
|
||||||
|
|
||||||
Stworzenie zmiennej
|
|
||||||
var variable = 20
|
|
||||||
|
|
||||||
Blok
|
|
||||||
Jako tablica
|
|
||||||
[1;2;3]
|
|
||||||
|
|
||||||
Jako odroczona ewaluacja
|
|
||||||
[say 42]
|
|
||||||
|
|
||||||
Jako funkcja anonimowa jednoparametrowa
|
|
||||||
[i | i * i ]
|
|
||||||
|
|
||||||
Poniższe zapisy są równoważne
|
|
||||||
[ say 42 ]
|
|
||||||
[| say 42 ]
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
Dostępne stałe
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
fn 1
|
|
||||||
dfn 3/2
|
|
||||||
hn 1/2
|
|
||||||
dhn 3/4
|
|
||||||
ddhn 7/8
|
|
||||||
qn 1/4
|
|
||||||
dqn 3/8
|
|
||||||
ddqn 7/16
|
|
||||||
en 1/8
|
|
||||||
den 3/16
|
|
||||||
dden 7/32
|
|
||||||
sn 1/16
|
|
||||||
dsn 3/32
|
|
||||||
tn 1/32
|
|
||||||
dtn 3/64
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
Dostępne funkcje
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
flat : ...items : any -> array
|
|
||||||
tworzy tablicę z dostarczonych elementów, rozsypując elementy indeksowalne
|
|
||||||
przykład:
|
|
||||||
flat 1 2 3 tworzy tablicę 1, 2, 3
|
|
||||||
flat [1;2] 2 3 tworzy tablicę 1, 2, 2, 3
|
|
||||||
flat [[1;2]; [3;4]] 5 6 tworzy tablicę [1;2], [3;4], 5, 6
|
|
||||||
|
|
||||||
|
|
||||||
if : condition: bool, block: block -> (eval block)
|
|
||||||
wywołuje block jeśli condition jest:
|
|
||||||
dla b: bool jest b == true
|
|
||||||
dla n: number jest n != 0
|
|
||||||
dla nil jest false
|
|
||||||
dla typu music, block, intrinsic, symbol zawsze prawdziwe
|
|
||||||
|
|
||||||
if : condition: Bool, then: Block, else: Block -> (eval then or eval else)
|
|
||||||
jeśli condition jest prawdziwe wg zasad wyżej wywołaj then
|
|
||||||
w innym przypadku wywołaj else
|
|
||||||
|
|
||||||
len : array -> number
|
|
||||||
zwraca ilość elementów w tablicy
|
|
||||||
Przykład:
|
|
||||||
len (flat 5 6 7) == 3
|
|
||||||
|
|
||||||
len : block -> number
|
|
||||||
zwraca ilość elementów (liczbę indeksowalnych pozycji) wewnątrz bloku
|
|
||||||
Przykład:
|
|
||||||
len [1;2;3] == 3
|
|
||||||
len [foo;bar] == 2
|
|
||||||
len [foo bar] == 1
|
|
||||||
|
|
||||||
play : music... -> nil
|
|
||||||
odtwarza sekwencyjnie otrzymane wartości muzyczne
|
|
||||||
|
|
||||||
chord : (collection | music)... -> music
|
|
||||||
tworzy akord z przekazanych wartości muzycznych
|
|
||||||
|
|
||||||
par : x: music -> xs: playable... -> nil
|
|
||||||
odtwarza dźwięk x równolegle z wszystkimi dźwiękami xs
|
|
309
doc/overview.md
Normal file
309
doc/overview.md
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
## Korzystanie z interpretera w systemie GNU/Linux
|
||||||
|
|
||||||
|
Uruchamiać interpreter można na dwa sposoby:
|
||||||
|
|
||||||
|
- w trybie interaktywnym poprzez polecenie `musique`
|
||||||
|
- w trybie wsadowym poprzez podanie nazw plików do programu musique `musique utwór_a.mq utwór_b.mq`
|
||||||
|
|
||||||
|
Pliki zawierające kod Musique mają według konwencji rozszerzenie `mq`.
|
||||||
|
|
||||||
|
Tryb interaktywny jak i wsadowy nie różnią się swoimi możliwościami. Można połączyć ich działanie poprzez podanie parametru `--repl` w trakcie uruchamiania interpretera.
|
||||||
|
|
||||||
|
Aby opuścić interpreter należy użyć skrótu klawiszowego `CTRL-D`, `CTRL-C` lub polecenia `:quit`.
|
||||||
|
|
||||||
|
Interpreter posiada historię poprzednich poleceń, którą można przechodzić przy pomocy strzałek.
|
||||||
|
|
||||||
|
### Przykłady uruchamiania i korzystania z interpretera
|
||||||
|
|
||||||
|
Uruchom wyłącznie tryb interaktywny:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ musique
|
||||||
|
> play c e g
|
||||||
|
```
|
||||||
|
|
||||||
|
Uruchom plik `examples/ode-to-joy.mq`, który odgrywa "Odę do radości":
|
||||||
|
|
||||||
|
```
|
||||||
|
$ musique examples/ode-to-joy.mq
|
||||||
|
```
|
||||||
|
|
||||||
|
Uruchom plik `examples/factorial.mq`, który wypisuje kolejne wartości silni, ale też tryb interaktywny, w którym wykorzystamy definicje z pliku:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ musique examples/factorial.mq
|
||||||
|
> factorial 5
|
||||||
|
120
|
||||||
|
```
|
||||||
|
|
||||||
|
## Podstawowe koncepty
|
||||||
|
|
||||||
|
### Komentarze
|
||||||
|
|
||||||
|
Komentarze pozwalają umieszczać opisy i _komentarze_ składające się z języka naturalnego wewnątrz kodu Musique. Są dwa rodzaje komentarzy: liniowe oraz wieloliniowe.
|
||||||
|
|
||||||
|
Komentarze liniowe rozpoczynają się od znaków `--` lub `#!` i kończą się wraz z zakończeniem linii.
|
||||||
|
|
||||||
|
Komentarze wieloliniowe rozpoczynają się od co najmniej trzech znaków `-` i kończą się na co najmniej 3 znakach `-`. Pozwala to na następujące kształty komentarzy:
|
||||||
|
|
||||||
|
```
|
||||||
|
-- komentarz do końca linii
|
||||||
|
say 42; -- komentarz do końca linii, wyrażenia przed nim są wykonywane
|
||||||
|
|
||||||
|
--- komentarz wieloliniowy
|
||||||
|
say 43 <- to nie zostanie wykonane
|
||||||
|
---
|
||||||
|
|
||||||
|
say 44;
|
||||||
|
|
||||||
|
----------------------------------------------
|
||||||
|
A tutaj mamy wieloliniowy komentarz, który
|
||||||
|
ma ładne obramowania
|
||||||
|
----------------------------------------------
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wartości w języku
|
||||||
|
|
||||||
|
Musique jest językiem dynamicznie typowanym - zmienne nie mają typu, wyłącznie wartości je mają.
|
||||||
|
|
||||||
|
__Typ__ jest to rodzaj wartości, determinujący w jaki sposób można je transformować, wyświetlać, grać czy w inny sposób przetwarzać.
|
||||||
|
|
||||||
|
Musique posiada kilka typów: _nil_, _bool_, _number_, _symbol_, _intrinsic_, _block_, _array_, _music_. Typ _nil_ ma pojedyńczą wartość, __nil__, która istnieje dla odróżnienia wartości od wszystkich innych wartości wartości oraz reprezentowania braku użytecznej wartości.
|
||||||
|
|
||||||
|
Typ logiczny _bool_, posiada dwie wartości: __true__ i __false__, reprezentujące odpowiednio prawdę i fałsz. __false__ nie jest jedyną metodą reprezentowania wartości fałszywej; w kontekście _warunku_ __0__, __false__, __nil__ są widziane jako fałszywe, stąd nazywane są wartościami fałszywymi (_false values_).
|
||||||
|
|
||||||
|
Typ liczbowy _number_ reprezentuje liczby wymierne, których licznik i mianownik mogą być 64-bitowymi liczbami całkowitymi. Sprawia to, że możliwym jest precyzyjne definiowanie ułamków oznaczających długość dżwięku jak `1/3` lub `3`.
|
||||||
|
|
||||||
|
Typ _symbol_ reprezentuje identyfikatory jak i stałe nazwane wewnątrz języka.
|
||||||
|
|
||||||
|
Typ funkcji wbudowanych _intrinsic_ jest używany do przechowywania funkcji napisanych wewnątrz interpretera, jak `play`, `note_on`, `par`, itp.
|
||||||
|
|
||||||
|
Typ blokowy _block_ reprezentuje kolekcję wartości, opcjonalnie sparemetryzowaną. Inaczej mówiąc blok, reprezentuje zarówno funkcje jak i tablice w Musique. Co ważne ewaluacja wnętrza bloku jest _leniwe_ - dopóki blok nie zostanie wywołany lub jego pole zindekowane, nie zostanie jego wnętrze wykonane. Blok posiadający parametry nie może zostać zindeksowany, gdyż jego wnętrze ulegnie zmianom w zależności od podanych parametrów.
|
||||||
|
|
||||||
|
Typ tablicowy _array_ reprezentuje kolekcję wartości, która w przeciwieństwie do bloków nie jest leniwa - w momencie tworzenia wszystkie wartości są już znane. Stosowana jest w celu przechowywania wyników transformacji bloków, gdyż transformowanie bloku oblicza jego wartości.
|
||||||
|
|
||||||
|
Typ muzyczny _music_ reprezentuje akord (w szczególności składający się z jednego dźwięku) w skali oferowanej przez MIDI. Najmniejszą jednostką jest półton, pojedyńczy dźwięk jest reprezentowany jako trójka (baza, opcjonalna oktawa, opcjonalna długość). Dźwięk w momencie grania może dostać domyślną wartość długości czy oktawy. Można także własnoręcznie ustawić oktawę i długość poprzez wywołanie dźwięku `c 4 (1/4)`. Jeden akord może zawierać wiele dźwięków o różnych długościach grania.
|
||||||
|
|
||||||
|
Funkcja wbudowana `typeof` wypisuje symbol reprezentujący dany typ.
|
||||||
|
|
||||||
|
### Odśmiecanie pamięci (garbage collection)
|
||||||
|
|
||||||
|
Język korzysta z automatycznego mechanizmu zarzadzania pamięcią. Sprawia to, że osoba korzystająca z pamięci nie musi przejmować się alokacją pamięci. Aktualny sposób zarzadzania pamięcią opiera się na wbudowanym w bibliotekę standardową języka C++ mechanizmu zliczania referencji. Nie jest on widziany jako ostateczny, a jako prototypowy. Może prowadzić to do nieoczekiwanego zachowania interpretera, objawiającego się wolnym działaniem i nadmiernym użytkowaniem pamięci.
|
||||||
|
|
||||||
|
## Język
|
||||||
|
|
||||||
|
Ta sekcja omawia składnię ("wygląd") oraz semantykę ("zachowanie") języka Musique. Jest to omówienie jakie programy są prawidłowe i co one znaczą.
|
||||||
|
|
||||||
|
### Składnia języka oraz literały
|
||||||
|
|
||||||
|
Kod języka Musique jest zakodowany jako UTF-8.
|
||||||
|
|
||||||
|
Musique jest językiem "free-form" - białe znaki są używane tylko do odróżnienia kolejnych słów i znaków języka, ale nie determinują jego znaczenia. Musique rozpoznaje wyłącznie białe znaki ASCII jako separatory - znaki jak niepodzielna spacja nie są rozpatrywane jako separatory.
|
||||||
|
|
||||||
|
Nazwy (identifikatory, _identifiers_) są dowolną sekwencją liter (w tym litery polskie; widzianych przez Unicode jako litery), liczb oraz znaków: `_'#$@`. Nie mogą rozpoczynać się cyfrą, nie mogą być literałem muzycznym lub zarezerwowanym identyfikatorem.
|
||||||
|
|
||||||
|
Następujące identyfikatory są zarezerwowane: `and` oraz `or`.
|
||||||
|
|
||||||
|
Musique jest językiem zwracającym uwagę na wysokość liter:
|
||||||
|
|
||||||
|
- `and` jest zarezerwowane, ale `And` nie jest.
|
||||||
|
- `c` jest literałem muzycznym, `C` może być identyfikatorem
|
||||||
|
|
||||||
|
#### Stałe liczbowe
|
||||||
|
|
||||||
|
Stała liczbowa (literał liczbowy) jest to ciąg cyfr, z potencjalnym ciągiem cyfr oznaczający część dziesiętną poprzedzony kropką.
|
||||||
|
|
||||||
|
Przykłady stałych liczbowych:
|
||||||
|
|
||||||
|
- `10.25` reprezentuje wartość `10` i `1/4`,
|
||||||
|
- `0` reprezentuje wartość `0`,
|
||||||
|
- `0.0` reprezentuje wartość `0`.
|
||||||
|
|
||||||
|
Musique posiada tylko jeden sposób sposób reprezentacji liczb dlatego `0` jest tym samym co `0.0`.
|
||||||
|
|
||||||
|
Musique __nie__ posiada stałych innych niż dziesiętne, także szesnastkowych (heksadecymalnych) czy ósemkowych.
|
||||||
|
|
||||||
|
#### Stałe muzyczne
|
||||||
|
|
||||||
|
Stałe muzyczne (literały muzyczne) jest to nazwa dźwięku z opcjonalnym przyrostkiem będącym ciągiem cyfr.
|
||||||
|
|
||||||
|
|
||||||
|
| Nazwa dźwięku | Wartość bazowa | Numer MIDI w oktawie 4 |
|
||||||
|
| :-: | :-: | :-: |
|
||||||
|
| __c__ | 0 | 60 |
|
||||||
|
| __d__ | 2 | 62 |
|
||||||
|
| __e__ | 4 | 64 |
|
||||||
|
| __f__ | 5 | 65 |
|
||||||
|
| __g__ | 7 | 67 |
|
||||||
|
| __a__ | 9 | 69 |
|
||||||
|
| __b__ | 11 | 71 |
|
||||||
|
|
||||||
|
Numer dźwięku może być modyfikowany o półton poprzez dodanie po nazwie dźwięku (co najmniej jednego):
|
||||||
|
|
||||||
|
- `#` lub `s` zwiększa o jeden półton numer dźwięku
|
||||||
|
- `b` lub `f` zmniejsza o jeden półton numer dźwięku
|
||||||
|
|
||||||
|
Numer dźwięku może być ujemny - może sprawić, że dźwięk "spadnie" do niższej oktawy.
|
||||||
|
|
||||||
|
Po nazwie dźwięku można przy pomocy liczb określić akord. Każda kolejna cyfra oznacza kolejny dźwięk w ramach akordu, liczony bezwględnie od dźwięku bazowego jako przesunięcie o daną liczbę półtonów. `c47` określa akord składający się z dźwięków `c`, `c+4`, `c+7` - akord C-dur.
|
||||||
|
|
||||||
|
### Zmienne
|
||||||
|
|
||||||
|
Zmienne są to miejsca przechowywania wartości.
|
||||||
|
|
||||||
|
Nazwa, określona przez symbol, reprezentuje odwołanie do stworzonej wcześniej zmiennej. Nie można używać zmiennych, które nie zostały wcześniej _zadeklarowane_.
|
||||||
|
|
||||||
|
Deklaracja zmiennych sprawia, że zmienna istnieje. Równocześnie z jej tworzeniem, można przypisać jej wartość.
|
||||||
|
|
||||||
|
```
|
||||||
|
x := 10;
|
||||||
|
y := 20;
|
||||||
|
|
||||||
|
say x y; -- wypisuje 10 20
|
||||||
|
|
||||||
|
t := x;
|
||||||
|
x = y;
|
||||||
|
y = t;
|
||||||
|
|
||||||
|
say x y; -- wypisuje 20 10
|
||||||
|
```
|
||||||
|
|
||||||
|
Zmienne mają zasięg leksykalny - mają dostęp tylko do zmiennych z kontekstu ich tworzenia, a nie np. z miejsca gdzie blok został wywołany.
|
||||||
|
|
||||||
|
### Wyrażenia
|
||||||
|
|
||||||
|
Musique wspiera następujące typy wyrażeń:
|
||||||
|
|
||||||
|
- sekwencję wyrażeń jak `foo; bar; foo hello`
|
||||||
|
- wyrażenia blokowe jak `[10;20;30]`
|
||||||
|
- wywołania funkcji jak `call_me maybe`
|
||||||
|
- binarne operacje jak: `10 + 20`
|
||||||
|
|
||||||
|
### Bloki
|
||||||
|
|
||||||
|
Są sekwencją wyrażeń. Każde kolejne wyrażenie oddzielone jest znakiem średnika `;`. Dla wygody, można stosować więcej niż jeden średnik do oddzielania wyrażeń (przypadkowe wciśnięcia nie są karane). Każy blok otoczony jest parą nawiasów kwadratowych `[]`, które determinują zasięg widoczności zadeklarowanych w nim zmiennych, w tym parametrów.
|
||||||
|
|
||||||
|
Blok może rozpoczynać się sekcją parametrów, która może zawierać wyłącznie symbole, a kończy się znakiem `|`. W momencie wywoływania bloku, każdemu parametrowi odpowiadać powinień argument, który nada parametrowi wartość. Literały muzyczne jak `c` __nie mogą__ zostać użyte jako parametry bloku.
|
||||||
|
|
||||||
|
Przykłady zastosowania bloków:
|
||||||
|
|
||||||
|
```
|
||||||
|
-- Blok, który nie przyjmuje żadnych parametrów i nie posiada żadnych wartości
|
||||||
|
[];
|
||||||
|
|
||||||
|
-- Blok, który nie przyjmuje żadnych parametrów, ale posiada wartość
|
||||||
|
x := [10];
|
||||||
|
say x.0; -- wypisuje 10
|
||||||
|
say (call x); -- wypisuje 10
|
||||||
|
|
||||||
|
-- Blok, który nie przyjmuje żadnych parametrów, ale posiada wiele wartości
|
||||||
|
x := [10; 20; 30];
|
||||||
|
say x.0; -- wypisuje 10
|
||||||
|
say (call x); -- wypisuje 30
|
||||||
|
|
||||||
|
-- Blok, który przyjmuje parametry i zwraca ich sumę
|
||||||
|
add := [x y | x + y ];
|
||||||
|
say (add 101 22); -- wypisuje 123
|
||||||
|
|
||||||
|
-- Blok, który odwołuje się do samego siebie
|
||||||
|
count_down := [n| say n; if (n >= 0) [ count_down (n-1) ] ];
|
||||||
|
count_down 10; -- wypisuje kolejne wartości od 10 do 0 włącznie
|
||||||
|
```
|
||||||
|
|
||||||
|
### Operacje binarne
|
||||||
|
|
||||||
|
#### Operacje logiczne
|
||||||
|
|
||||||
|
Musique wspera sume logiczną `or` oraz iloczyn logiczny `and`. Ponadto dostępne są operatory równości `==` oraz `!=`.
|
||||||
|
|
||||||
|
#### Operacje liczbowe
|
||||||
|
|
||||||
|
Musique wspiera standardowe operacje arytmetyczne (`+`, `-`, `*`, `/` oraz potęga '**') oraz porównania (`<`, `<=`, `==`, `!=`, `>=`, `>`).
|
||||||
|
|
||||||
|
#### Operacje na wartościach muzycznych
|
||||||
|
|
||||||
|
Wspierane są operatory porównania `<`, `<=`, `==`, `!=`, `>=`, `>`. Porównywać można wartości tylko o tym samym stopniu wypełnienia informacji - jeśli jedna z wartości nie ma wyspecjalizowanej podwartości jak oktawy czy długości nie można ich nawzajem porównać.
|
||||||
|
|
||||||
|
- __Dodawanie półtonów__ `a + b` gdzie `a` jest wartością muzyczną (liczbową), a `b` jest wartością liczbową (muzyczną).
|
||||||
|
- __Odejmowanie półtonów__ `a - b` gdzie `a` jest wartością muzyczną (liczbową), a `b` jest wartością liczbową (muzyczną).
|
||||||
|
|
||||||
|
Wartości muzyczne i liczbowe można zestawiać koło siebie:
|
||||||
|
|
||||||
|
- `c 1 2` tworzy `c` w oktawie 1 o długości 2
|
||||||
|
- `c c` tworzy sekwencję dźwięków `[c;c]`
|
||||||
|
- `c e g` tworzy sekwencję dźwięków `[c;e;g]`
|
||||||
|
- `c 4 e 5 g 4` tworzy sekwencję dźwięków: c w oktawie 4, e w oktawie 5 i g w oktawie 4
|
||||||
|
|
||||||
|
## Funkcje wbudowane
|
||||||
|
|
||||||
|
### Funkcje muzyczne
|
||||||
|
|
||||||
|
`par A B...` pozwala na zagranie wartości muzycznej `A` przez całą długość odtwarzania częsci `B`.
|
||||||
|
|
||||||
|
`sim a b` gra równocześnie część `A` i `B`.
|
||||||
|
|
||||||
|
`play A...` odtwarza sekwenencyjne kolejne grupy dźwięków.
|
||||||
|
|
||||||
|
Gdy funkcje `par` lub `play` dostaną tablicę wartości muzycznych tablice zostaną odtworzone sekwencyjnie. Inaczej mówiąc `play a [c;e;d] b ≡ play a c e d b`.
|
||||||
|
|
||||||
|
#### Modyfikacja kontekstu
|
||||||
|
|
||||||
|
`bpm A` ustawia długość `A` odpowiadającą ćwierćnucie w uderzeniach na minutę.
|
||||||
|
|
||||||
|
`len A` ustawia domyślną długość nuty jako `A`
|
||||||
|
|
||||||
|
`oct A` ustawia domyślną oktawę
|
||||||
|
|
||||||
|
### Funkcje sterowania przepływem
|
||||||
|
|
||||||
|
`if <condition> <then> <else>` wykonuje blok `then` jeśli `condition` jest rozpatrywane jako prawdziwe. Jeśli blok `<else>` zostanie dostarczony, to zostanie wywołany dla warunku fałszywego.
|
||||||
|
|
||||||
|
```
|
||||||
|
if true [say 42] [say 10] -- wyświetla 42
|
||||||
|
if false [say 42] [say 10] -- wyświetla 10
|
||||||
|
say (if false [42] [10]) -- wyświetla 10
|
||||||
|
say (if false [42]) -- wyświetla nil
|
||||||
|
```
|
||||||
|
|
||||||
|
### Funkcje matematyczne
|
||||||
|
|
||||||
|
`max` znajduje maksimum z podanych wartości, a `min` znajdume minimum. W momencie podania tablic, znajduje maksimum / minumum z danej tablicy i pozostałych wartości przekazanych do funkcji.
|
||||||
|
|
||||||
|
__Wartości muzyczne, logiczne i liczbowe__ są widziane jako porównywalne tylko gdy mają ten sam typ: `c < d`, `0 < 1`, `false < true` itp.
|
||||||
|
|
||||||
|
### Funkcje tablicowe
|
||||||
|
|
||||||
|
`permute` generuje kolejną permutację tablicy.
|
||||||
|
|
||||||
|
`reverse` zwraca odwróconą tablicę.
|
||||||
|
|
||||||
|
`sort` zwraca tablicę z posortowanymi elementami
|
||||||
|
|
||||||
|
`partition` dzieli podane wartości wg predykatu, tak, że zwraca dwuelementową tablicę, w którym pierwszym elementem jest tablica wartości dla których predykat zwrócił prawdę, a drugim elementem jest tablica wartości dla których predykat zwrócił fałsz.
|
||||||
|
|
||||||
|
```
|
||||||
|
say (partition [i | i > 5] 1 2 3 4 5 [1; 2; 3; 8] 9 0)
|
||||||
|
-- wypisuje: [[8; 9]; [1; 2; 3; 4; 5; 1; 2; 3; 0]]
|
||||||
|
```
|
||||||
|
|
||||||
|
`shuffle` zwraca tablicę z losową kolejnością elementów.
|
||||||
|
|
||||||
|
`flat` spłaszcza przekazane tablice (o jeden rząd)
|
||||||
|
|
||||||
|
```
|
||||||
|
say (flat 1 2 3);
|
||||||
|
-- wypisuje [1;2;3]
|
||||||
|
say (flat [1;2;3]);
|
||||||
|
-- wypisuje [1;2;3]
|
||||||
|
say (flat [1;2;3] 4 [5;6]);
|
||||||
|
-- wypisuje [1;2;3;4;5;6]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Funkcje MIDI
|
||||||
|
|
||||||
|
`note_on <kanał> <nuta> <siła>` wysyła komunikat _Note on_.
|
||||||
|
|
||||||
|
`note_off <kanał> <nuta>` wysyła komunikat _Note off_.
|
||||||
|
|
||||||
|
`pgmchange` (znane także jako `instrument`) wysyła komunikat _Program Change_.
|
||||||
|
|
@ -8,8 +8,8 @@ if exists("b:current_syntax")
|
|||||||
finish
|
finish
|
||||||
endif
|
endif
|
||||||
|
|
||||||
syn keyword musiqueVariableDeclaration var
|
syn keyword musiqueVariableDeclaration :=
|
||||||
syn keyword musiqueOperators * + - / < <= == >= > != .
|
syn keyword musiqueOperators * + - / < <= == >= > != . ** and or
|
||||||
|
|
||||||
syn match musiqueParameterSplitter display "|"
|
syn match musiqueParameterSplitter display "|"
|
||||||
syn match musiqueExpressionDelimiter display ";"
|
syn match musiqueExpressionDelimiter display ";"
|
||||||
@ -18,7 +18,7 @@ syn match musiqueInteger display "[0-9][0-9_]*"
|
|||||||
|
|
||||||
syn keyword musiqueConstant true false nil
|
syn keyword musiqueConstant true false nil
|
||||||
|
|
||||||
syn keyword musiqueDefaultBuiltins if len play permute par shuffle chord bpm oct note_on note_off flat update
|
syn keyword musiqueDefaultBuiltins bpm call ceil chord down flat floor fold for hash if incoming instrument len max min mix note_off note_on nprimes oct par partition permute pgmchange play program_change range reverse rotate round shuffle sim sort try typeof uniq unique up update
|
||||||
syn keyword musiqueLinuxBuiltins say
|
syn keyword musiqueLinuxBuiltins say
|
||||||
|
|
||||||
syn match musiqueComment "--.*$"
|
syn match musiqueComment "--.*$"
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
"Für Elise in A Minor" by Ludwig van Beethoven
|
"Für Elise in A Minor" by Ludwig van Beethoven
|
||||||
|
WIP implemntation
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
oct 5; bpm 72; len (1/16);
|
oct 5; bpm 72; len (1/16);
|
||||||
|
|
||||||
subsection1 := [ n |
|
subsection1 := [
|
||||||
sim (a 4 en) (a 2 e 3 a 3);
|
sim (a 4 en) (a 2 e 3 a 3);
|
||||||
play [oct 4; c e a];
|
play [oct 4; c e a];
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ section1 := [ n |
|
|||||||
play (e d#);
|
play (e d#);
|
||||||
play (e d# e b 4 d c);
|
play (e d# e b 4 d c);
|
||||||
|
|
||||||
subsection1 0;
|
call subsection1;
|
||||||
|
|
||||||
if (n == 1)
|
if (n == 1)
|
||||||
[ sim (a 4 qn) (a 2 e 3 a 3); ]
|
[ sim (a 4 qn) (a 2 e 3 a 3); ]
|
||||||
@ -51,7 +52,7 @@ section2 := [ n |
|
|||||||
play (d# e d# e d#);
|
play (d# e d# e d#);
|
||||||
play (e d# e b 4 d c);
|
play (e d# e b 4 d c);
|
||||||
|
|
||||||
subsection1 0;
|
call subsection1;
|
||||||
|
|
||||||
if (n == 1)
|
if (n == 1)
|
||||||
[ sim (a 4 en) (a 2 e 3 a 3)
|
[ sim (a 4 en) (a 2 e 3 a 3)
|
||||||
|
3
scripts/definitions
Executable file
3
scripts/definitions
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
awk -F'"' '/global\.force_define\(/ { print $2 }' $1 | sort | uniq
|
35
scripts/release
Executable file
35
scripts/release
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e -o pipefail
|
||||||
|
|
||||||
|
Suffix="$(date +"%Y-%m-%d")"
|
||||||
|
Target="release_$Suffix"
|
||||||
|
|
||||||
|
|
||||||
|
if [ -d "$Target" ]; then
|
||||||
|
rm -rf "$Target"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$Target"
|
||||||
|
|
||||||
|
if ! [ -f bin/musique ]; then
|
||||||
|
make bin/musique
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Copy bin/musique, examples, license and documentation"
|
||||||
|
|
||||||
|
cp bin/musique "$Target"/
|
||||||
|
cp LICENSE "$Target"/LICENSE
|
||||||
|
cp -r examples "$Target"/examples
|
||||||
|
|
||||||
|
lowdown -s doc/overview.md -m "title:Omówienie języka Musique" -o "$Target"/overview.html
|
||||||
|
lowdown -s doc/functions.md -m "title:Lista funkcji języka Musique" -o "$Target"/functions.html
|
||||||
|
|
||||||
|
echo "Copy source code"
|
||||||
|
|
||||||
|
git clone --quiet --depth=1 "$(git remote -v | awk '{ print $2 }' | head -n1)" "$Target"/source_code
|
||||||
|
rm -rf "$Target"/source_code/.git
|
||||||
|
|
||||||
|
echo "Boundle it all up"
|
||||||
|
|
||||||
|
zip -q -r "musique_$Suffix.zip" "$Target"/*
|
@ -156,7 +156,7 @@ enum class Range_Direction { Up, Down };
|
|||||||
|
|
||||||
/// Create range according to direction and specification, similar to python
|
/// Create range according to direction and specification, similar to python
|
||||||
template<Range_Direction dir>
|
template<Range_Direction dir>
|
||||||
Result<Value> builtin_range(Interpreter&, std::vector<Value> args)
|
static Result<Value> builtin_range(Interpreter&, std::vector<Value> args)
|
||||||
{
|
{
|
||||||
using N = Shape<Value::Type::Number>;
|
using N = Shape<Value::Type::Number>;
|
||||||
using NN = Shape<Value::Type::Number, Value::Type::Number>;
|
using NN = Shape<Value::Type::Number, Value::Type::Number>;
|
||||||
@ -920,11 +920,33 @@ static Result<Value> builtin_mix(Interpreter &i, std::vector<Value> args)
|
|||||||
return Value::from(std::move(result));
|
return Value::from(std::move(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call operator. Calls first argument with remaining arguments
|
||||||
|
static Result<Value> builtin_call(Interpreter &i, std::vector<Value> args)
|
||||||
|
{
|
||||||
|
auto const guard = Guard<1> {
|
||||||
|
.name = "call",
|
||||||
|
.possibilities = {
|
||||||
|
"(function, ...args) -> any"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (args.size() == 0) {
|
||||||
|
return guard.yield_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto callable = args.front();
|
||||||
|
Try(guard(is_callable, callable));
|
||||||
|
args.erase(args.begin());
|
||||||
|
|
||||||
|
return callable(i, std::move(args));
|
||||||
|
}
|
||||||
|
|
||||||
void Interpreter::register_builtin_functions()
|
void Interpreter::register_builtin_functions()
|
||||||
{
|
{
|
||||||
auto &global = *Env::global;
|
auto &global = *Env::global;
|
||||||
|
|
||||||
global.force_define("bpm", ctx_read_write_property<&Context::bpm>);
|
global.force_define("bpm", ctx_read_write_property<&Context::bpm>);
|
||||||
|
global.force_define("call", builtin_call);
|
||||||
global.force_define("ceil", apply_numeric_transform<&Number::ceil>);
|
global.force_define("ceil", apply_numeric_transform<&Number::ceil>);
|
||||||
global.force_define("chord", builtin_chord);
|
global.force_define("chord", builtin_chord);
|
||||||
global.force_define("down", builtin_range<Range_Direction::Down>);
|
global.force_define("down", builtin_range<Range_Direction::Down>);
|
||||||
|
Loading…
Reference in New Issue
Block a user