Compare commits
4 Commits
add-readme
...
new-parser
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49e4c4487e | ||
|
|
e7674a4834 | ||
|
|
ed2c8dc6dd | ||
|
|
f91e2a75de |
3
.gitignore
vendored
@@ -1,4 +1,3 @@
|
||||
__pycache__/
|
||||
*.mus
|
||||
.idea/*
|
||||
venv/
|
||||
.idea/*
|
||||
16
Pipfile
@@ -1,16 +0,0 @@
|
||||
[[source]]
|
||||
name = "pypi"
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[packages]
|
||||
sounddevice = "*"
|
||||
soundfile = "*"
|
||||
numpy = "*"
|
||||
matplotlib = "*"
|
||||
tkinter = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
||||
180
Pipfile.lock
generated
@@ -1,180 +0,0 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "92b0c636f6ac9be9b32aa25b1cdc96dcbe85602d5c68a2084dc39d25392540b6"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.7"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"cffi": {
|
||||
"hashes": [
|
||||
"sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774",
|
||||
"sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d",
|
||||
"sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90",
|
||||
"sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b",
|
||||
"sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63",
|
||||
"sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45",
|
||||
"sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25",
|
||||
"sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3",
|
||||
"sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b",
|
||||
"sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647",
|
||||
"sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016",
|
||||
"sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4",
|
||||
"sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb",
|
||||
"sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753",
|
||||
"sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7",
|
||||
"sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9",
|
||||
"sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f",
|
||||
"sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8",
|
||||
"sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f",
|
||||
"sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc",
|
||||
"sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42",
|
||||
"sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3",
|
||||
"sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909",
|
||||
"sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45",
|
||||
"sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d",
|
||||
"sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512",
|
||||
"sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff",
|
||||
"sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201"
|
||||
],
|
||||
"version": "==1.12.3"
|
||||
},
|
||||
"cycler": {
|
||||
"hashes": [
|
||||
"sha256:1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d",
|
||||
"sha256:cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"
|
||||
],
|
||||
"version": "==0.10.0"
|
||||
},
|
||||
"kiwisolver": {
|
||||
"hashes": [
|
||||
"sha256:05b5b061e09f60f56244adc885c4a7867da25ca387376b02c1efc29cc16bcd0f",
|
||||
"sha256:26f4fbd6f5e1dabff70a9ba0d2c4bd30761086454aa30dddc5b52764ee4852b7",
|
||||
"sha256:3b2378ad387f49cbb328205bda569b9f87288d6bc1bf4cd683c34523a2341efe",
|
||||
"sha256:400599c0fe58d21522cae0e8b22318e09d9729451b17ee61ba8e1e7c0346565c",
|
||||
"sha256:47b8cb81a7d18dbaf4fed6a61c3cecdb5adec7b4ac292bddb0d016d57e8507d5",
|
||||
"sha256:53eaed412477c836e1b9522c19858a8557d6e595077830146182225613b11a75",
|
||||
"sha256:58e626e1f7dfbb620d08d457325a4cdac65d1809680009f46bf41eaf74ad0187",
|
||||
"sha256:5a52e1b006bfa5be04fe4debbcdd2688432a9af4b207a3f429c74ad625022641",
|
||||
"sha256:5c7ca4e449ac9f99b3b9d4693debb1d6d237d1542dd6a56b3305fe8a9620f883",
|
||||
"sha256:682e54f0ce8f45981878756d7203fd01e188cc6c8b2c5e2cf03675390b4534d5",
|
||||
"sha256:79bfb2f0bd7cbf9ea256612c9523367e5ec51d7cd616ae20ca2c90f575d839a2",
|
||||
"sha256:7f4dd50874177d2bb060d74769210f3bce1af87a8c7cf5b37d032ebf94f0aca3",
|
||||
"sha256:8944a16020c07b682df861207b7e0efcd2f46c7488619cb55f65882279119389",
|
||||
"sha256:8aa7009437640beb2768bfd06da049bad0df85f47ff18426261acecd1cf00897",
|
||||
"sha256:939f36f21a8c571686eb491acfffa9c7f1ac345087281b412d63ea39ca14ec4a",
|
||||
"sha256:9733b7f64bd9f807832d673355f79703f81f0b3e52bfce420fc00d8cb28c6a6c",
|
||||
"sha256:a02f6c3e229d0b7220bd74600e9351e18bc0c361b05f29adae0d10599ae0e326",
|
||||
"sha256:a0c0a9f06872330d0dd31b45607197caab3c22777600e88031bfe66799e70bb0",
|
||||
"sha256:acc4df99308111585121db217681f1ce0eecb48d3a828a2f9bbf9773f4937e9e",
|
||||
"sha256:b64916959e4ae0ac78af7c3e8cef4becee0c0e9694ad477b4c6b3a536de6a544",
|
||||
"sha256:d3fcf0819dc3fea58be1fd1ca390851bdb719a549850e708ed858503ff25d995",
|
||||
"sha256:d52e3b1868a4e8fd18b5cb15055c76820df514e26aa84cc02f593d99fef6707f",
|
||||
"sha256:db1a5d3cc4ae943d674718d6c47d2d82488ddd94b93b9e12d24aabdbfe48caee",
|
||||
"sha256:e3a21a720791712ed721c7b95d433e036134de6f18c77dbe96119eaf7aa08004",
|
||||
"sha256:e8bf074363ce2babeb4764d94f8e65efd22e6a7c74860a4f05a6947afc020ff2",
|
||||
"sha256:f16814a4a96dc04bf1da7d53ee8d5b1d6decfc1a92a63349bb15d37b6a263dd9",
|
||||
"sha256:f2b22153870ca5cf2ab9c940d7bc38e8e9089fa0f7e5856ea195e1cf4ff43d5a",
|
||||
"sha256:f790f8b3dff3d53453de6a7b7ddd173d2e020fb160baff578d578065b108a05f"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"matplotlib": {
|
||||
"hashes": [
|
||||
"sha256:1febd22afe1489b13c6749ea059d392c03261b2950d1d45c17e3aed812080c93",
|
||||
"sha256:31a30d03f39528c79f3a592857be62a08595dec4ac034978ecd0f814fa0eec2d",
|
||||
"sha256:4442ce720907f67a79d45de9ada47be81ce17e6c2f448b3c64765af93f6829c9",
|
||||
"sha256:796edbd1182cbffa7e1e7a97f1e141f875a8501ba8dd834269ae3cd45a8c976f",
|
||||
"sha256:934e6243df7165aad097572abf5b6003c77c9b6c480c3c4de6f2ef1b5fdd4ec0",
|
||||
"sha256:bab9d848dbf1517bc58d1f486772e99919b19efef5dd8596d4b26f9f5ee08b6b",
|
||||
"sha256:c1fe1e6cdaa53f11f088b7470c2056c0df7d80ee4858dadf6cbe433fcba4323b",
|
||||
"sha256:e5b8aeca9276a3a988caebe9f08366ed519fff98f77c6df5b64d7603d0e42e36",
|
||||
"sha256:ec6bd0a6a58df3628ff269978f4a4b924a0d371ad8ce1f8e2b635b99e482877a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.1.1"
|
||||
},
|
||||
"numpy": {
|
||||
"hashes": [
|
||||
"sha256:03f2ebcbffcce2dec8860633b89a93e80c6a239d21a77ae8b241450dc21e8c35",
|
||||
"sha256:078c8025da5ab9e8657edc9c2a1e9642e06e953bc7baa2e65c1aa9d9dfb7e98b",
|
||||
"sha256:0fbfa98c5d5c3c6489cc1e852ec94395d51f35d9ebe70c6850e47f465038cdf4",
|
||||
"sha256:1c841033f4fe6801648180c3033c45b3235a8bbd09bc7249010f99ea27bb6790",
|
||||
"sha256:2c0984a01ddd0aeec89f0ce46ef21d64761048cd76c0074d0658c91f9131f154",
|
||||
"sha256:4c166dcb0fff7cb3c0bbc682dfb5061852a2547efb6222e043a7932828c08fb5",
|
||||
"sha256:8c2d98d0623bd63fb883b65256c00454d5f53127a5a7bcdaa8bdc582814e8cb4",
|
||||
"sha256:8cb4b6ae45aad6d26712a1ce0a3f2556c5e1484867f9649e03496e45d6a5eba4",
|
||||
"sha256:93050e73c446c82065b7410221b07682e475ac51887cd9368227a5d944afae80",
|
||||
"sha256:a3f6b3024f8826d8b1490e6e2a9b99e841cd2c375791b1df62991bd8f4c00b89",
|
||||
"sha256:bede70fd8699695363f39e86c1e869b2c8b74fb5ef135a67b9e1eeebff50322a",
|
||||
"sha256:c304b2221f33489cd15a915237a84cdfe9420d7e4d4828c78a0820f9d990395c",
|
||||
"sha256:f11331530f0eff69a758d62c2461cd98cdc2eae0147279d8fc86e0464eb7e8ca",
|
||||
"sha256:fa5f2a8ef1e07ba258dc07d4dd246de23ef4ab920ae0f3fa2a1cc5e90f0f1888",
|
||||
"sha256:fb6178b0488b0ce6a54bc4accbdf5225e937383586555604155d64773f6beb2b",
|
||||
"sha256:fd5e830d4dc31658d61a6452cd3e842213594d8c15578cdae6829e36ad9c0930"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.17.1"
|
||||
},
|
||||
"pycparser": {
|
||||
"hashes": [
|
||||
"sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"
|
||||
],
|
||||
"version": "==2.19"
|
||||
},
|
||||
"pyparsing": {
|
||||
"hashes": [
|
||||
"sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80",
|
||||
"sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4"
|
||||
],
|
||||
"version": "==2.4.2"
|
||||
},
|
||||
"python-dateutil": {
|
||||
"hashes": [
|
||||
"sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb",
|
||||
"sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e"
|
||||
],
|
||||
"version": "==2.8.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
||||
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
|
||||
],
|
||||
"version": "==1.12.0"
|
||||
},
|
||||
"sounddevice": {
|
||||
"hashes": [
|
||||
"sha256:8d0571349f9a438a97f2c69da760f195cf5ddf2351072199cc1dfede4785a207",
|
||||
"sha256:a0dda9dea9a5038ec0dafee4cdebd6d9a09086405d4833a7e3f6b18c109f89f3",
|
||||
"sha256:a71cd3daabc8cb13e0ec9a29e7d4ba9b707386f3c81b3501b20f64209bcaece7",
|
||||
"sha256:b038315e3497e01b1cb22630bc9b5025fcfad40e5ef7c125a9d565befa7220e0",
|
||||
"sha256:c340d0a68945439571a13b287bd11b2d2884b61cd47cc5de8356d88221edf580"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.3.13"
|
||||
},
|
||||
"soundfile": {
|
||||
"hashes": [
|
||||
"sha256:181393f8daac38bda997c4284b760bcd726dc0e847f620020d7bf2d3d538a985",
|
||||
"sha256:3f90971bb1884575ada9a0731e878c91cc1ffde14a778f0857deaa2fd04849ac",
|
||||
"sha256:637f6218c867b8cae80f6989634a0813b416b3e6132480d056e6e5a89a921571",
|
||||
"sha256:7fe04272cbfb94ab648acb0db31ace0800f5a4cf46e9d45b4d71ddb15abce1a0",
|
||||
"sha256:80a3d2ed37199ffa7066c097d7b82b8413922e22870b62b54dc264bf0169f4c2"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.10.2"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
println("Adeste Fideles");
|
||||
println("John Francis Wade");
|
||||
|
||||
s1 = [@g, @g:2, @d, @g, @a:2, @d:2, @h, @a, @h, @c5, @h:2, @a, @g];
|
||||
s2 = [@g:2, @f#, @e, @f#, @g, @a, @h, @f#:2, @e:4d, @d:8, @d:2d, 4];
|
||||
s3 = [@d5:2, @c5, @h, @c5:2, @h:2, @a, @h, @g, @a, @f#:4d, @e:8, @d];
|
||||
s4 = [@g, @g, @f#, @g, @a, @g:2, @d, @h, @h, @a, @h, @c5, @h:2, @a];
|
||||
s5 = [@h, @c5, @h, @a, @g, @f#:2, @g, @c5, @h:2, @a:4d, @g:8, @g:1];
|
||||
|
||||
S = s1 + s2 + s3 + s4 + s5;
|
||||
|
||||
a1 = [@d, @d:2, @d, @d, @e:2, @d:2, @d, @d, @d, @e, @d:2, @d, @h3];
|
||||
a2 = [@h3, @c#, @d, @c#, @d, @d, @d, @d, @d:2, @c#:4d, @d:8, @d:2d, 4];
|
||||
a3 = [@d:2, @e:8, @f#:8, @g, @g, @f#, @g:2, @d, @d, @e, @e, @d:2, @d];
|
||||
a4 = [@d, @d:1, @d:2d, @d, @d:1, @d:2d];
|
||||
a5 = [@g, @f#, @g, @d, @d:8, @c#:8, @d:2, @d, @e, @d:2, @d:4d, @h3:8, @h3:1];
|
||||
|
||||
A = a1 + a2 + a3 + a4 + a5;
|
||||
|
||||
t1 = [@h3, @h3:2, @h3, @h3, @c:2, @a3:2, @g3, @a3, @g3, @g3, @g3:2, @f#3, @g3];
|
||||
t2 = [@g3:2, @a3, @a3, @a3, @g3, @f#3, @d3, @a3:2, @g3:4d, @f#3:8, @f#3:2d, 4];
|
||||
t3 = [@h3:2, @c, @d, @c:2, @d:2, @d, @g3, @h3, @c, @a3:2, @f#3];
|
||||
t4 = [@h3, @h3, @a3, @h3, @c, @h3:2d, @g3, @g3, @f#3, @g3, @a3, @g3:2, @f#3];
|
||||
t5 = [@d, @d, @d, @a3, @a3, @a3:2, @g3:2, @g3:2, @f#3:4d, @g3:8, @g3:1];
|
||||
|
||||
T = t1 + t2 + t3 + t4 + t5;
|
||||
|
||||
b1 = [@g3, @g3:2, @h3, @g3, @g3:2, @f#3:2, @g3, @f#3, @g3, @c3, @d3:2, @d3, @e3];
|
||||
b2 = [@e3:2, @d3, @a2, @d3, @h2, @f#2, @g2, @a2:2, @a2:4d, @d3:8, @d2:2d, 4];
|
||||
b3 = [@h3:2, @a3, @g3, @a3:2, @g3:2, @f#3, @g3, @e3, @c3, @d3:2, @d3];
|
||||
b4 = [4, 1, 1, 1, 2, 4];
|
||||
b5 = [@g3, @a3, @g3, @f#3, @e3, @d3, @c3, @h2, @c3, @d3:2, @d3:4d, @g2:8, @g2:1];
|
||||
|
||||
B = b1 + b2 + b3 + b4 + b5;
|
||||
|
||||
synth({ tuning -> 431, attack -> 100, decay -> 1.2, overtones -> [0.7, 0, 0.2, 0.1] }, S, A, T, B);
|
||||
@@ -1,42 +0,0 @@
|
||||
println("Bohemian Rhapsody :: part");
|
||||
println("by Queen");
|
||||
|
||||
m1 = [@d:8, @d:8, @d:2, 8, @b3:8, @c:8, @d:16, @d:16, @d, 4, 8, @d:16, @d:16];
|
||||
m2 = [@eb:8, @f:8, @eb:8, @d:8, @c, @c:8, @d:8, @eb:16, @f:8, @eb:8d, @d:8, @c, 4, @d:8, @d:8, @d:2, @d:8, @f:8];
|
||||
m3 = [@a:8d, @g:16, @g:2, 8, @g:8, @b:8, @b:8, @b:8, @b:8, @b:8d, @g:16, @d:8d, @c:16, @c:2, 2];
|
||||
M1 = [1, 1] + m1 + m2 + m3;
|
||||
|
||||
p_B = [@d:8, @f3:8, @b3:8, @d:8, @g:8, @f3:8, @f:8, @f:8];
|
||||
p_g = [@d:8, @g3:8, @b3:8, @d:8, @a:8, @g3:8, @g:8, @b3:8];
|
||||
p_c = [@g:8, @c:8, @eb:8, @g:8, @d5:8, @c:8, @c5:8, @c:8];
|
||||
p_cF = [@b:8, @c:8, @eb:8, @g:8, @a:8, @eb:8, @f:8, @c:8];
|
||||
p1 = [@eb:8, @c:8, @eb:8, @g:8, @eb:8, @g:8, @eb:8, @g:8, @eb:8, @a3:8, @eb:8, @g:8, @eb:8, @g:8, @eb:8, @g:8];
|
||||
|
||||
P1 = p_B + p_B + p_B + p_g + p_c + p_cF + p_B + p_g + p1;
|
||||
|
||||
b1 = [@b3:1, @g3:1, @c3:1, @c3:2, @f3:2];
|
||||
b2 = [@b3:2d, @a3, @g3:1, @c3:2, @h2, @b2, @a2:2, @ab2, @g2];
|
||||
B1 = [@b3:1, @b3:1] + b1 + b2;
|
||||
|
||||
# Eb
|
||||
m1 = [@g:16, @g:16, @g:2, 8, @f:8, @g:16, @ab:16, @g:2, 4, 8, @g:16, @g:16, @ab:8d, @g:16, @g:8, @f:16, @f:2, @b3:16];
|
||||
m2 = [@b3:8, @f:8, @f:8, @g:16, @g:8d, @ab:8, @ab:8, @b:16, @ab:16, @ab:8, @g:8, 8, @f:16, @g:16, @b:4d, @f:16, @g:16];
|
||||
m3 = [@eb:4d, @b3:16, @b3:16, @h3:8, @db:8, @h3:16, @db:16, @h3:8, @b3:2, 2];
|
||||
M2 = m1 + m2 + m3;
|
||||
|
||||
p_Eb = [@b:8, @eb:8, @eb5:8, @eb:8, @b:8, @eb:8, @f:8, @b:8];
|
||||
p_f = [@ab:8, @f:8, @ab:8, @ab:8, @ab:8, @eb:8, @ab:8, @d:8];
|
||||
p_B = [@d, @f, @g, @ab];
|
||||
p_EbB = [@b:8, @eb:8, @eb5:8, @eb:8, @b:8, @d:8, @b:8, @d:8];
|
||||
p_cf = [@g:8, @c:8, @g:8, @c:8, @h3:2];
|
||||
P2 = p_Eb + p_c + p_f + p_B + p_EbB + p_cf;
|
||||
|
||||
b1 = [@eb3:2d, @d3, @c3:1, @f3:4d, @e3:8, @eb3, @d3, @b2, @b2, @b2, @b2, @eb3:2, @d3:2];
|
||||
b2 = [@c2:2, @f2:2, @eb2:2, 2];
|
||||
B2 = b1 + b2;
|
||||
|
||||
M = M1 + M2;
|
||||
P = P1 + P2;
|
||||
B = B1 + B2;
|
||||
|
||||
synth({ tuning -> 432, bpm -> 72, overtones -> [0.5, 0.3, 0.15, 0.05], decay -> 0.8 }, transpose(12, M), P, B);
|
||||
@@ -1,120 +0,0 @@
|
||||
println("Star Wars :: Cantina Band");
|
||||
println("by John Williams");
|
||||
|
||||
cb1 = [@a, @d5, @a, @d5] + [@a:8, @d5, @a:8, 8, @g#:8, @a];
|
||||
cb2 = [@a:8, @g#:8, @a:8, @g:8, 8, @f#:8, @g:8, @gb:8];
|
||||
cb3 = [@f:4d, @d:2, 8];
|
||||
cb4 = [@g:8, 8, @g:4d, @f#:8, @g];
|
||||
cb5 = [@c5:8, @b, @a, @g:4d];
|
||||
cb6 = [@c5:8, 8, @c5:4d, @a:8, @g];
|
||||
cb7 = [@f:4d, @d:2, 8];
|
||||
cb8 = [@d:2, @f:2, @a:2, @c5:2];
|
||||
cb9 = [@eb5, @d5, @g#:8, @a, @f:8];
|
||||
|
||||
CB1 = cb1 + cb2 + cb3 + cb1 + cb4 + cb5 + cb1 + cb6 + cb7 + cb8 + cb9 + [1];
|
||||
|
||||
cb11 = 2 ^ [8, @a5, @f5:8, @a5:8, 8, 4];
|
||||
cb12 = [8, @a5, @f5:8, @g#5:8, @a5, @f5:8];
|
||||
cb13 = [@f5:4d, @d5:2, 8];
|
||||
cb14 = [8, @a5, @f5:8, @g#5:8, @a5, @g5:8];
|
||||
cb15 = [@g5:2, @c5:2];
|
||||
cb16 = [@b:8, @d5:8, @f5, @h:8, @d5:8, @f5];
|
||||
cb17 = [@g#:8, @a5, @d5:2, 8];
|
||||
cb18 = [@d:8, @f:8, @h:8, @d5:8, @g#:8, @a, @f:8];
|
||||
cb19 = [@f:2d, 4];
|
||||
|
||||
CB2 = cb11 + cb12 + cb13 + cb11 + cb14 + cb15 + cb11 + cb12 + cb13 + cb16 + cb17 + cb18 + cb19;
|
||||
|
||||
cb20 = [@f, 8, @ab, @f:8, @g];
|
||||
cb21 = [8, @f:8, @ab:8, @f:8, @g:8, @f:8, @ab:8, @d:8];
|
||||
cb22 = [@f, 8, @ab, @f:8, @g];
|
||||
cb23 = [@f:8, @f:8, @ab:8, @f:8, @g:8, @f:8, @ab:8, @f:8];
|
||||
cb24 = [@g:8, @f:8, @ab:8, @f:8, @g:8, @f:8, @ab:8, @d:8];
|
||||
cb25 = [@f:8, @f:8, @ab:8, @f:8, @ab:8, @f, @f:8, @f:2d, 4];
|
||||
|
||||
CB3 = cb20 + cb21 + cb22 + cb21 + cb22 + cb21 + cb23 + cb24 + cb22 + cb21 + cb22 + cb21 + cb22 + cb21 + cb25;
|
||||
|
||||
cb26 = [@c5, 8, @e5:8, 4, @g5];
|
||||
cb27 = [@g5:8, @g5, @g5:8, @g5, @e5:8, @c5:8];
|
||||
cb28 = [@f5, @f5:8, @f5:8, @f5:8, @g5, @a5:8, @a5:1];
|
||||
cb29 = [@e5, @e5, @g5:8, @g5, @c5:8];
|
||||
cb30 = [@c5:8, @e5, @c5:8, @e5, @g5];
|
||||
cb31 = [@f5, @f5:8, @f5, @g5, @a5:8, @a5:1];
|
||||
cb32 = [@b5, @b5, @d6, @b5:8, @db6:8];
|
||||
cb33 = [@db6:8, @db6:8, @b5, @db6, @b5];
|
||||
cb34 = [@f5, @f5, @f5:8, @ab5, @d6:8, @d6:1];
|
||||
cb35 = [8, @b, @d5:8, @g5, @g5];
|
||||
cb36 = [8, @e5, 8, @e5, @e5];
|
||||
cb37 = [8, @f5, @f5:8, @f5, @f5:8, @f5:8];
|
||||
cb38 = [@f5:8, @f5, @f5:8, @f5:8, @f5:8, @f5];
|
||||
|
||||
CB4 = cb26 + cb27 + cb28 + cb29 + cb30 + cb31 + cb32 + cb33 + cb34 + cb35 + cb36 + cb37 + cb38;
|
||||
|
||||
cb39 = [@ab:8, @gb:8, @ab:8, @gb:8, @ab:8, @gb:8, @ab:8, @gb:8];
|
||||
cb40 = [@ab:8, @db5, @ab:8, @db5, @ab:8, @db5:8];
|
||||
cb41 = [8, @ab:8, @b:8, @h:8, @c5:8, @h:8, @b:8, 8];
|
||||
cb42 = [@ab:8, @db5, @ab:8, @db5, @ab:8, @a:8];
|
||||
cb43 = [@b:8, @a:8, @b:4d, @a:8, @b:8, @a:8];
|
||||
cb44 = [@b:8, @a:8, @b:8, @h:8, @c5:8, 8, @gb:8, @g:8];
|
||||
cb45 = [@b:8, @a:8, @b:4d, @a:8, @b:8, @h:8];
|
||||
cb46 = [@c5:8, @g:8, @e:8, @c:8, 8, @c:8, @db:8, @c:8];
|
||||
cb47 = [@db:8, @b3, @db:8, @fb:8, @db, @fb:8];
|
||||
cb48 = [@f:8, @e:8, @f:8, @gb:8, @g:8, @c, @g:8];
|
||||
cb49 = [@ab:8, @g:8, @ab:8, @a:8, @b:8, @a:8, @b:8, @h:8];
|
||||
cb50 = [@c5:8, @c5:8, 4, @c5:8, @c5:8, 4];
|
||||
cb51 = [@c5, @e5:2, @f5:8, @db5:8];
|
||||
cb52 = [@ab:8, @f:8, @fb:8, @eb:8, @d:8, 4, @gb:8];
|
||||
cb53 = [@c5:8, @c5, @gb:8, @c5:8, @c5, @h:8];
|
||||
cb54 = [@c5:8, @c5, @h:8, @c5:8, @c5, @c5:8];
|
||||
cb55 = [@db5:8, @fb:8, @db5:4d, @fb:8, @db5:8, @fb:8];
|
||||
cb56 = [@db5:8, @fb:8, @db5:8, @fb:8, @eb:8, @c5, @c5:8];
|
||||
cb57 = [@db5:8, @fb:8, @db5:8, @fb:8, @eb:8, @c5, @h3:8];
|
||||
cb58 = [@b3:8, @db:8, @gb:8, @b:8, @c:8, @e:8, @g:8, @c5:8];
|
||||
cb59 = [@db5:8, @db, @c:8, @db, 4];
|
||||
cb60 = [4, @a3, @b3, @a3, @b3, @a3, @gb3:8, @f3:8, @d3:8, 8];
|
||||
cb61 = [8, @a3, @a3, @a3, @a3, @a3, @a3:8, @a3:8, @a3];
|
||||
|
||||
CB5 = cb39 + cb40 + cb41 + cb39 + cb42 + cb43 + cb44 + cb39 + cb42 + cb45 + cb46 + cb47 + cb48 + cb49 + cb50 + cb50 + cb51 + cb52 + cb53 + cb54 + cb55 + cb56 + cb55 + cb56 + cb55 + cb57 + cb58 + cb59 + cb60 + cb60 + cb60;
|
||||
|
||||
CB = CB1 + CB2 + CB3 + (2 ^ CB4) + CB5;
|
||||
|
||||
b1 = (3 ^ [@d3, 4, @a2, 4]) + [@f3, 4, @c3, 4, @d3, 4, @a2, 4, @d3, 4, @a2, 4, @g2, 4, @g2, 4];
|
||||
b2 = [@c3, @d3, @d#3, @e3, @d3, 4, @a2, 4, @d3, 4, @a2, 4, @c3, 4, @c3, 4];
|
||||
b3 = [@f3, 4, @c3, 4, @b2, 4, @b2, 4, @f3, 4, @d3, 4, @g3, 4, @c3, 4, @f3, @e3, @d3, @c3];
|
||||
|
||||
B1 = b1 + b2 + b3;
|
||||
|
||||
b4 = (3 ^ [@d3, 4, @a2, 4]) + [@d3:4d, @g#2:4d, @a2];
|
||||
b5 = (3 ^ [@d3, 4, @a2, 4]) + [@eb3:2, @c3, @c3];
|
||||
b6 = (4 ^ [@d3, 4, @a2, 4]);
|
||||
b7 = [@b2:8, @b2:8, 4, @h2:8, @h2:8, 4, @c3:4d, @d3:8, 8, @d3:8, @d3, @g2, 4, @c3:4d, @f3:4d, @e3, @d3, @c3];
|
||||
|
||||
B2 = b4 + b5 + b6 + b7;
|
||||
|
||||
b8 = 3 ^ [@d3, @c3, @b2, @a2, @g2, @f2, @e2, @d2];
|
||||
b9 = [@d3, 4, 2, 2, 4, @a2];
|
||||
b10 = [@d3, @b2, @a2, @a2, @d3:8, 8, 4, 2];
|
||||
|
||||
B3 = b8 + b9 + b8 + b10;
|
||||
|
||||
b11 = [@c3, 4, @g2, 4, @c3, 8, @b2:4d, @g2, @f2, 4, @c3, 4, @f3, 8, @e3:4d, @d3];
|
||||
b12 = [@c3, 4, @g3, 4, @c3, 8, @b2:4d, @g2, @f2, 4, @c3, 4, @d3, 8, @f#2:4d, @a2];
|
||||
b13 = [@b2, 4, @b2, 4, @h2, 4, @h2, 4, @c3, 4, @c3, 4, @d3, 8, @d3:4d, @f#2];
|
||||
b14 = [@g2, 4, @d3, 4, @c3, 8, @c3:4d, @g3, @f3, 4, @db3, 4, @f3, @f3, @e3, @d3];
|
||||
|
||||
B4 = b11 + b12 + b13 + b14;
|
||||
|
||||
b15 = [@db3, @c3, @b2, @ab2, @gb2, @f2, @eb2, @db2, @db3, @b2, @a2, @ab2];
|
||||
b16 = [@db3, @c3, @b2, @ab2, @gb2, @f2, @eb2, @db2, @eb2, @e2, @f2, @gb2];
|
||||
b17 = [@e2, @d2, @h2, @ab2, @h2, @ab2, @f2, @eb2, @db2, @c2, @b1, @ab1];
|
||||
# ^ or B?
|
||||
b18 = [@gb2, @gb2, @gb2, @db3, @c3, @c3, @e3, @g3, @gb3, @gb3, @g3, @g3];
|
||||
b19 = [@ab3, @db3, @c3, @c3, @f3, @c3, @gb3, @gb3, @c3, 4, @c3, 4];
|
||||
b20 = [@f3, 4, @f3, 4, @c3, @c3, 4, @db3:8, @f3:8, @ab3:8, @a3:8, @b3:8, @h3:8, @c:8, 8, 8, 16, @g3:16];
|
||||
b21 = [@c3, 4, @c3, 4, @f3, 4, @f3, 4, @gb2, 4, @ab2, 4, @a2, 4, @db3, 4, @gb2, 4, @ab2, 4, @a2, 4, @db3, 4, @d, 4, @eb, 4];
|
||||
b22 = [@e3, 4, @f3, 4, @gb3, 4, @g3, 4, @db3, 4, @db3, 4];
|
||||
B5 = b15 + b16 + b17 + b18 + b19 + b20 + b21 + b22;
|
||||
|
||||
B = B1 + B2 + B3 + (2 ^ B4) + B5;
|
||||
|
||||
synth({ tuning -> 432, bpm -> 270 }, flat(CB), flat(B));
|
||||
@@ -1,31 +0,0 @@
|
||||
println("Les Anges dans nos campagnes");
|
||||
|
||||
s = [@a, @a, @a, @c5, @c5:4d, @b:8, @a:2, @a, @g, @a, @c5, @a:4d, @g:8, @f:2];
|
||||
sc = [@c5:2, @d5:8, @c5:8, @b:8, @a:8, @b:2, @c5:8, @b:8, @a:8, @g:8, @a:2, @b:8, @a:8, @g:8, @f:8, @g:4d, @c:8, @c:2, @f, @g, @a, @b];
|
||||
sca = [@a:2, @g, 4];
|
||||
scb = [@a:2, @g:2, @f:2d, 4];
|
||||
|
||||
S = flat(2^s, sc, sca, sc, scb);
|
||||
|
||||
a = [@f, @f, @e, @e, @g, @e, @f:2, @f, @e, @f, @f, @f, @e, @f:2];
|
||||
ac = [@f, @a:8, @g:8, @f:2d, @g:8, @f:8, @e:2d, @f:8, @e:8, @d:2, @c:4d, @c:8, @c:2, @c, @e, @f, @g];
|
||||
aca = [@f:2, @e, 4];
|
||||
acb = [@f:2, @e:2, @c:2d, 4];
|
||||
|
||||
A = flat(2^a, ac, aca, ac, acb);
|
||||
|
||||
t = [@c, @c, @c, @c, @d, @c, @c:2, @c, @c, @c, @c, @c:4d, @b3:8, @a3:2];
|
||||
tc = [@a3:2, @d:1, @c:1, @b3:2, @g3, @f3, @e3:2, @f3, @c, @c, @d];
|
||||
tca = [@c:2, @c, 4];
|
||||
tcb = [@c:2d, @b3, @a3:2d, 4];
|
||||
|
||||
T = flat(2^t, tc, tca, tc, tcb);
|
||||
|
||||
b = [@f3, @f3, @a3, @a3, @g3, @c3, @f3:2, @f3, @c3, @f3, @a3, @c, @c3, @f3:2];
|
||||
bc = [@f3:2, @d3, @f3, @g3:2, @c3, @e3, @f3:2, @b2, @d3, @e3, @d3, @c3, @b2, @a2, @c3, @f3, @b2];
|
||||
bca = [@c3:2, @c3, 4];
|
||||
bcb = [@c3:1, @f3:2d, 4];
|
||||
|
||||
B = flat(2^b, bc, bca, bc, bcb);
|
||||
|
||||
synth({ tuning -> 432, overtones -> [0.6, 0.3, 0.07, 0.03], attack -> 200, decay -> 0.6 }, S, A, T, B);
|
||||
@@ -1,18 +0,0 @@
|
||||
println("Per Crucem - canon");
|
||||
|
||||
d1 = [@d:2, @d:2, @c:2, @f:4d, @f:8, @f, @f, @e, @d, @e:2, @d:2];
|
||||
d2 = [@d:8, @f:8, @a:8, @d5:8, @b:8, @a:8, @g, @c:8, @e:8, @g:8, @c5:8, @a:8, @g:8, @f, @b3:8, @d:8, @f:8, @b:8, @g:8, @f:8, @e, @a, @e, @f:2];
|
||||
d3 = [@a:2, @b:2, @c5:2, @a:4d, @a:8, @b, @f, @g, @g, @a, @e, @f:2];
|
||||
d4 = [@d5:8, @c5:8, @b:8, @a:8, @g:8, @a:8, @b, @c5:8, @b:8, @a:8, @g:8, @f:8, @g:8, @a, @b:8, @a:8, @g:8, @f:8, @e:8, @f:8, @g, @a, @e, @f:2];
|
||||
d5 = [@d5:2, @d5:2, @c5:2, @c5:2, @d5:8, @c5:8, @b:8, @a:8, @b, @b, @a:2, @a:2];
|
||||
d6 = [@d:8, @d:8, @d:8, @d:8, @g:8, @g:8, @g, @c:8, @c:8, @c:8, @c:8, @f:8, @f:8, @f, @b3:8, @b3:8, @b3:8, @b3:8, @e:8, @e:8, @e, @a3, @a3, @d:2];
|
||||
|
||||
p = [1, 1, 1, 1];
|
||||
|
||||
S = d1 + d2 + d3 + d4 + d5 + d6 + d1 + d2 + d3;
|
||||
A = p + d1 + d2 + d3 + d4 + d5 + d6 + d1 + d2;
|
||||
T = p + p + d1 + d2 + d3 + d4 + d5 + d6 + d1;
|
||||
B = p + p + p + d1 + d2 + d3 + d4 + d5 + d6;
|
||||
|
||||
wv = wave(S, A, transpose(-12, T), transpose(-12, B));
|
||||
synth(wv);
|
||||
@@ -1,31 +0,0 @@
|
||||
println("Narodził się nam Zbawiciel / Quem pastores laudavere");
|
||||
println("mel.: XIV w.");
|
||||
println("sł.: XV - XVI w.");
|
||||
println("harm.: Bartłomiej Pluta");
|
||||
|
||||
s1 = [@f:2, @a, @c5:2, @a, @c5:2, @d5, @c5, @g:2];
|
||||
s2 = [@a:2, @c5, @b:2, @g, @f:2, @d, @e, @c:2];
|
||||
s3 = [@a:2, @b, @c5:2, @d5, @c5:2, @g, @a, @f:2];
|
||||
s4 = [@b:2, @b, @a, @g, @a, @f, @d, @e, @f:2d];
|
||||
|
||||
a1 = [@c:2, @f, @g:2, @f, @f, @g, @f, @f, @f, @e];
|
||||
a2 = [@f, @e, @eb, @d:2, @c, @d:2, @d, @c, @c, @b3];
|
||||
a3 = [@c:2, @c, @f, @d, @g, @g:2, @e, @e, @d:2];
|
||||
a4 = [@f:2, @f, @f, @e, @f, @c:2, @c, @c:2d];
|
||||
|
||||
t1 = [@a, @b, @c5, @c5, @b, @c5, @a:2, @b, @a, @c5:2];
|
||||
t2 = [@c5:2, @a, @b:2, @c5, @d5, @c, @b, @g, @g:2];
|
||||
t3 = [@f, @a, @g, @a:2, @b, @b:2, @g, @g, @a:2];
|
||||
t4 = [@d5, @db5, @db5, @c5, @b, @a, @g:2, @b, @a:2d];
|
||||
|
||||
b1 = [@f:2, @f, @e:2, @f, @f:2, @f, @c, @c:2];
|
||||
b2 = [@f:2, @f#, @g, @f, @e, @d, @f, @g, @c, @e:2];
|
||||
b3 = [@f:2, @e, @f, @f#, @g, @e, @d, @c, @c#, @d, @c];
|
||||
b4 = [@b3:2, @b, @c:2, @c, @c:2, @c, @f:2d];
|
||||
|
||||
S = s1 + s2 + s3 + s4;
|
||||
A = a1 + a2 + a3 + a4;
|
||||
T = transpose(-12, t1 + t2 + t3 + t4);
|
||||
B = transpose(-12, b1 + b2 + b3 + b4);
|
||||
|
||||
synth({ overtones -> [0.6, 0.25, 0.1] + (2 ^ 0.0) + [0.05], attack -> 50, decay -> 1 }, S, A, T, B);
|
||||
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 103 KiB |
BIN
img/plots/c.png
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 26 KiB |
@@ -1,2 +0,0 @@
|
||||
You have to have installed `PortAudio` in order to use app.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.ast.parser import Parsers
|
||||
from smnp.token.type import TokenType
|
||||
from smnp.util.singleton import SingletonParser
|
||||
|
||||
|
||||
class Atom(Node):
|
||||
@@ -27,10 +28,6 @@ class IntegerLiteral(Atom):
|
||||
pass
|
||||
|
||||
|
||||
class FloatLiteral(Atom):
|
||||
pass
|
||||
|
||||
|
||||
class StringLiteral(Atom):
|
||||
pass
|
||||
|
||||
@@ -47,63 +44,60 @@ class TypeLiteral(Atom):
|
||||
pass
|
||||
|
||||
|
||||
def IntegerParser(input):
|
||||
return Parser.terminal(TokenType.INTEGER, createNode=IntegerLiteral.withValue)(input)
|
||||
|
||||
|
||||
def FloatParser(input):
|
||||
return Parser.terminal(TokenType.FLOAT, createNode=FloatLiteral.withValue)(input)
|
||||
|
||||
|
||||
def StringParser(input):
|
||||
return Parser.terminal(TokenType.STRING, createNode=StringLiteral.withValue)(input)
|
||||
|
||||
|
||||
def NoteParser(input):
|
||||
return Parser.terminal(TokenType.NOTE, createNode=NoteLiteral.withValue)(input)
|
||||
|
||||
|
||||
def BoolParser(input):
|
||||
return Parser.terminal(TokenType.BOOL, createNode=BoolLiteral.withValue)(input)
|
||||
|
||||
|
||||
def TypeLiteralParser(input):
|
||||
return Parser.terminal(TokenType.TYPE, createNode=TypeLiteral.withValue)(input)
|
||||
|
||||
|
||||
def LiteralParser(input):
|
||||
return Parser.oneOf(
|
||||
IntegerParser,
|
||||
FloatParser,
|
||||
StringParser,
|
||||
NoteParser,
|
||||
BoolParser,
|
||||
TypeLiteralParser,
|
||||
name="literal"
|
||||
)(input)
|
||||
|
||||
|
||||
def AtomParser(input):
|
||||
from smnp.ast.node.identifier import IdentifierParser
|
||||
from smnp.ast.node.list import ListParser
|
||||
from smnp.ast.node.map import MapParser
|
||||
from smnp.ast.node.expression import ExpressionParser
|
||||
|
||||
parentheses = Parser.allOf(
|
||||
Parser.terminal(TokenType.OPEN_PAREN),
|
||||
Parser.doAssert(ExpressionParser, "expression"),
|
||||
Parser.terminal(TokenType.CLOSE_PAREN),
|
||||
createNode=lambda open, expr, close: expr,
|
||||
name="grouping parentheses"
|
||||
@SingletonParser
|
||||
def IntegerParser():
|
||||
return Parsers.oneOf(
|
||||
Parsers.terminal(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)),
|
||||
Parsers.allOf(
|
||||
Parsers.terminal(TokenType.MINUS),
|
||||
Parsers.terminal(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)),
|
||||
createNode=lambda minus, integer: IntegerLiteral.withValue(-integer.value, minus.pos),
|
||||
name="negativeInteger"
|
||||
),
|
||||
name="int"
|
||||
)
|
||||
|
||||
return Parser.oneOf(
|
||||
parentheses,
|
||||
LiteralParser,
|
||||
IdentifierParser,
|
||||
ListParser,
|
||||
MapParser,
|
||||
|
||||
@SingletonParser
|
||||
def StringParser():
|
||||
return Parsers.terminal(TokenType.STRING, createNode=StringLiteral.withValue)
|
||||
|
||||
|
||||
@SingletonParser
|
||||
def NoteParser():
|
||||
return Parsers.terminal(TokenType.NOTE, createNode=NoteLiteral.withValue)
|
||||
|
||||
|
||||
@SingletonParser
|
||||
def BoolParser():
|
||||
return Parsers.terminal(TokenType.BOOL, createNode=BoolLiteral.withValue)
|
||||
|
||||
|
||||
@SingletonParser
|
||||
def TypeParser():
|
||||
return Parsers.terminal(TokenType.TYPE, createNode=TypeLiteral.withValue)
|
||||
|
||||
|
||||
@SingletonParser
|
||||
def LiteralParser():
|
||||
return Parsers.oneOf(
|
||||
IntegerParser(),
|
||||
StringParser(),
|
||||
NoteParser(),
|
||||
BoolParser(),
|
||||
TypeParser(),
|
||||
name="literal"
|
||||
)
|
||||
|
||||
|
||||
@SingletonParser
|
||||
def AtomParser():
|
||||
from smnp.ast.node.identifier import IdentifierParser
|
||||
|
||||
return Parsers.oneOf(
|
||||
LiteralParser(),
|
||||
IdentifierParser(),
|
||||
name="atom"
|
||||
)(input)
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -9,9 +9,11 @@ class Block(Node):
|
||||
|
||||
|
||||
def BlockParser(input):
|
||||
return Parser.loop(
|
||||
Parser.terminal(TokenType.OPEN_CURLY),
|
||||
parser = Parser.loop(
|
||||
Parser.terminalParser(TokenType.OPEN_CURLY),
|
||||
Parser.doAssert(StatementParser, f"statement or '{TokenType.CLOSE_CURLY.key}'"),
|
||||
Parser.terminal(TokenType.CLOSE_CURLY),
|
||||
Parser.terminalParser(TokenType.CLOSE_CURLY),
|
||||
createNode=lambda open, statements, close: Block.withChildren(statements, open.pos)
|
||||
)(input)
|
||||
)
|
||||
|
||||
return Parser(parser, "block", [parser])(input)
|
||||
|
||||
32
smnp/ast/node/chain.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from smnp.ast.node.list import ListParser
|
||||
from smnp.ast.node.operator import BinaryOperator
|
||||
from smnp.ast.node.valuable import Valuable
|
||||
from smnp.ast.parser import Parsers
|
||||
from smnp.token.type import TokenType
|
||||
from smnp.util.singleton import SingletonParser
|
||||
|
||||
|
||||
class Chain(Valuable):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@SingletonParser
|
||||
def ChainParser():
|
||||
from smnp.ast.node.atom import AtomParser
|
||||
|
||||
itemParser = Parsers.oneOf(
|
||||
ListParser,
|
||||
#MapParser,
|
||||
AtomParser,
|
||||
name="chainItem"
|
||||
)
|
||||
|
||||
return Parsers.leftAssociativeOperatorParser(
|
||||
itemParser,
|
||||
[TokenType.DOT],
|
||||
itemParser,
|
||||
lambda left, op, right: Chain.withValue(BinaryOperator.withValues(left, op, right)),
|
||||
name="chain"
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from smnp.ast.node.expression import ExpressionParser
|
||||
from smnp.ast.node.expression import MaxPrecedenceExpressionParser
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.node.none import NoneNode
|
||||
from smnp.ast.node.statement import StatementParser
|
||||
@@ -46,23 +46,23 @@ class IfElse(Node):
|
||||
|
||||
def IfElseStatementParser(input):
|
||||
ifStatementParser = Parser.allOf(
|
||||
Parser.terminal(TokenType.IF),
|
||||
Parser.terminal(TokenType.OPEN_PAREN),
|
||||
ExpressionParser,
|
||||
Parser.terminal(TokenType.CLOSE_PAREN),
|
||||
Parser.terminalParser(TokenType.IF),
|
||||
Parser.terminalParser(TokenType.OPEN_PAREN),
|
||||
MaxPrecedenceExpressionParser,
|
||||
Parser.terminalParser(TokenType.CLOSE_PAREN),
|
||||
StatementParser,
|
||||
createNode=lambda _, __, condition, ___, ifStatement: IfElse.createNode(ifStatement, condition),
|
||||
name="if statement"
|
||||
)
|
||||
|
||||
ifElseStatementParser = Parser.allOf(
|
||||
Parser.terminal(TokenType.IF),
|
||||
Parser.terminal(TokenType.OPEN_PAREN, doAssert=True),
|
||||
Parser.doAssert(ExpressionParser, "expression"),
|
||||
Parser.terminal(TokenType.CLOSE_PAREN, doAssert=True),
|
||||
Parser.doAssert(StatementParser, "statement"),
|
||||
Parser.terminal(TokenType.ELSE),
|
||||
Parser.doAssert(StatementParser, "statement"),
|
||||
Parser.terminalParser(TokenType.IF),
|
||||
Parser.terminalParser(TokenType.OPEN_PAREN),
|
||||
MaxPrecedenceExpressionParser,
|
||||
Parser.terminalParser(TokenType.CLOSE_PAREN),
|
||||
StatementParser,
|
||||
Parser.terminalParser(TokenType.ELSE),
|
||||
StatementParser,
|
||||
createNode=lambda _, __, condition, ___, ifStatement, ____, elseStatement: IfElse.createNode(ifStatement, condition, elseStatement),
|
||||
name="if-else statement"
|
||||
)
|
||||
|
||||
@@ -1,128 +1,63 @@
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.node.none import NoneNode
|
||||
from smnp.ast.node.operator import BinaryOperator, Operator
|
||||
from smnp.ast.node.operator import BinaryOperator
|
||||
from smnp.ast.node.term import TermParser
|
||||
from smnp.ast.node.valuable import Valuable
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class Sum(BinaryOperator):
|
||||
class Expression(Valuable):
|
||||
pass
|
||||
|
||||
|
||||
class Relation(BinaryOperator):
|
||||
pass
|
||||
|
||||
|
||||
class And(BinaryOperator):
|
||||
pass
|
||||
|
||||
|
||||
class Or(BinaryOperator):
|
||||
pass
|
||||
|
||||
|
||||
class Loop(BinaryOperator):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
self.children.extend([NoneNode(), NoneNode()])
|
||||
|
||||
@property
|
||||
def parameters(self):
|
||||
return self[3]
|
||||
|
||||
@parameters.setter
|
||||
def parameters(self, value):
|
||||
self[3] = value
|
||||
|
||||
@property
|
||||
def filter(self):
|
||||
return self[4]
|
||||
|
||||
@filter.setter
|
||||
def filter(self, value):
|
||||
self[4] = value
|
||||
|
||||
@classmethod
|
||||
def loop(cls, left, parameters, operator, right, filter):
|
||||
node = cls(left.pos)
|
||||
node.left = left
|
||||
node.parameters = parameters
|
||||
node.operator = operator
|
||||
node.right = right
|
||||
node.filter = filter
|
||||
return node
|
||||
|
||||
|
||||
class LoopParameters(Node):
|
||||
pass
|
||||
|
||||
|
||||
def ExpressionWithoutLoopParser(input):
|
||||
expr1 = Parser.leftAssociativeOperatorParser(
|
||||
TermParser,
|
||||
[TokenType.PLUS, TokenType.MINUS],
|
||||
TermParser,
|
||||
lambda left, op, right: Sum.withValues(left, op, right)
|
||||
)
|
||||
|
||||
expr2 = Parser.leftAssociativeOperatorParser(
|
||||
expr1,
|
||||
[TokenType.RELATION, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE],
|
||||
expr1,
|
||||
lambda left, op, right: Relation.withValues(left, op, right)
|
||||
)
|
||||
|
||||
expr3 = Parser.leftAssociativeOperatorParser(
|
||||
expr2,
|
||||
[TokenType.AND],
|
||||
expr2,
|
||||
lambda left, op, right: And.withValues(left, op, right)
|
||||
)
|
||||
|
||||
return Parser.leftAssociativeOperatorParser(
|
||||
expr3,
|
||||
[TokenType.OR],
|
||||
expr3,
|
||||
lambda left, op, right: Or.withValues(left, op, right)
|
||||
)(input)
|
||||
|
||||
|
||||
def LoopParser(input):
|
||||
from smnp.ast.node.identifier import IdentifierLiteralParser
|
||||
from smnp.ast.node.iterable import abstractIterableParser
|
||||
from smnp.ast.node.statement import StatementParser
|
||||
|
||||
loopParameters = Parser.allOf(
|
||||
Parser.terminal(TokenType.AS),
|
||||
Parser.oneOf(
|
||||
Parser.wrap(IdentifierLiteralParser, lambda id: LoopParameters.withChildren([id], id.pos)),
|
||||
abstractIterableParser(LoopParameters, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, IdentifierLiteralParser)
|
||||
),
|
||||
createNode=lambda asKeyword, parameters: parameters,
|
||||
name="loop parameters"
|
||||
)
|
||||
|
||||
loopFilter = Parser.allOf(
|
||||
Parser.terminal(TokenType.PERCENT),
|
||||
Parser.doAssert(ExpressionWithoutLoopParser, "filter as bool expression"),
|
||||
createNode=lambda percent, expr: expr,
|
||||
name="loop filter"
|
||||
)
|
||||
|
||||
return Parser.allOf(
|
||||
ExpressionWithoutLoopParser,
|
||||
Parser.optional(loopParameters),
|
||||
Parser.terminal(TokenType.CARET, createNode=Operator.withValue),
|
||||
StatementParser,
|
||||
Parser.optional(loopFilter),
|
||||
createNode=Loop.loop,
|
||||
name="caret-loop"
|
||||
)(input)
|
||||
|
||||
|
||||
def ExpressionParser(input):
|
||||
return Parser.oneOf(
|
||||
LoopParser,
|
||||
ExpressionWithoutLoopParser
|
||||
return Parser.leftAssociativeOperatorParser(
|
||||
TermParser,
|
||||
[TokenType.PLUS, TokenType.MINUS],
|
||||
TermParser,
|
||||
lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right))
|
||||
)(input)
|
||||
|
||||
|
||||
def Expression2Parser(input):
|
||||
return Parser.leftAssociativeOperatorParser(
|
||||
ExpressionParser,
|
||||
[TokenType.RELATION],
|
||||
ExpressionParser,
|
||||
lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right))
|
||||
)(input)
|
||||
|
||||
|
||||
def Expression3Parser(input):
|
||||
return Parser.leftAssociativeOperatorParser(
|
||||
Expression2Parser,
|
||||
[TokenType.AND],
|
||||
Expression2Parser,
|
||||
lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right))
|
||||
)(input)
|
||||
|
||||
|
||||
def Expression4Parser(input):
|
||||
from smnp.ast.node.condition import IfElse
|
||||
exprParser = Parser.leftAssociativeOperatorParser(
|
||||
Expression3Parser,
|
||||
[TokenType.OR],
|
||||
Expression3Parser,
|
||||
lambda left, op, right: Expression.withValue(BinaryOperator.withValues(left, op, right))
|
||||
)
|
||||
|
||||
ifElseExpression = Parser.allOf(
|
||||
exprParser,
|
||||
Parser.terminalParser(TokenType.IF),
|
||||
Expression4Parser,
|
||||
Parser.terminalParser(TokenType.ELSE),
|
||||
Expression4Parser,
|
||||
createNode=lambda ifNode, _, condition, __, elseNode: IfElse.createNode(ifNode, condition, elseNode)
|
||||
)
|
||||
|
||||
return Parser.oneOf(
|
||||
ifElseExpression,
|
||||
exprParser,
|
||||
)(input)
|
||||
|
||||
|
||||
MaxPrecedenceExpressionParser = Expression4Parser
|
||||
@@ -1,88 +1,70 @@
|
||||
from smnp.ast.node.block import Block
|
||||
from smnp.ast.node.function import FunctionDefinitionParser
|
||||
from smnp.ast.node.identifier import IdentifierLiteralParser
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.node.none import NoneNode
|
||||
from smnp.ast.node.type import TypeParser
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class Extend(Node):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
self.children = [NoneNode(), NoneNode(), NoneNode()]
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self[0]
|
||||
|
||||
@type.setter
|
||||
def type(self, value):
|
||||
self[0] = value
|
||||
|
||||
@property
|
||||
def variable(self):
|
||||
return self[1]
|
||||
|
||||
@variable.setter
|
||||
def variable(self, value):
|
||||
self[1] = value
|
||||
|
||||
@property
|
||||
def methods(self):
|
||||
return self[2]
|
||||
|
||||
@methods.setter
|
||||
def methods(self, value):
|
||||
self[2] = value
|
||||
|
||||
@classmethod
|
||||
def withValues(cls, pos, type, variable, methods):
|
||||
node = cls(pos)
|
||||
node.type = type
|
||||
node.variable = variable
|
||||
node.methods = methods
|
||||
return node
|
||||
|
||||
|
||||
def ExtendParser(input):
|
||||
|
||||
simpleExtend = Parser.allOf(
|
||||
Parser.terminal(TokenType.EXTEND),
|
||||
TypeParser,
|
||||
Parser.terminal(TokenType.AS),
|
||||
IdentifierLiteralParser,
|
||||
Parser.terminal(TokenType.WITH),
|
||||
Parser.doAssert(Parser.wrap(FunctionDefinitionParser, lambda method: Block.withChildren([ method ], method.pos)), "method definition"),
|
||||
createNode=lambda extend, type, _, variable, __, methods: Extend.withValues(extend.pos, type, variable, methods),
|
||||
name="simple extend"
|
||||
)
|
||||
|
||||
multiExtend = Parser.allOf(
|
||||
Parser.terminal(TokenType.EXTEND),
|
||||
Parser.doAssert(TypeParser, "type being extended"),
|
||||
Parser.terminal(TokenType.AS, doAssert=True),
|
||||
Parser.doAssert(IdentifierLiteralParser, "variable name"),
|
||||
Parser.doAssert(MethodsDeclarationParser, f"block with methods definitions or '{TokenType.WITH.key}' keyword"),
|
||||
createNode=lambda extend, type, _, variable, methods: Extend.withValues(extend.pos, type, variable, methods),
|
||||
name="multiple extend"
|
||||
)
|
||||
|
||||
|
||||
return Parser.oneOf(
|
||||
simpleExtend,
|
||||
multiExtend,
|
||||
name="extend"
|
||||
)(input)
|
||||
|
||||
|
||||
def MethodsDeclarationParser(input):
|
||||
return Parser.loop(
|
||||
Parser.terminal(TokenType.OPEN_CURLY),
|
||||
Parser.doAssert(FunctionDefinitionParser, f"method definition or '{TokenType.CLOSE_CURLY.key}'"),
|
||||
Parser.terminal(TokenType.CLOSE_CURLY),
|
||||
createNode=lambda open, methods, close: Block.withChildren(methods, open.pos),
|
||||
name="methods block"
|
||||
)(input)
|
||||
|
||||
# from smnp.ast.node.block import BlockNode
|
||||
# from smnp.ast.node.function import FunctionDefinitionNode
|
||||
# from smnp.ast.node.identifier import IdentifierNode
|
||||
# from smnp.ast.node.none import NoneNode
|
||||
# from smnp.ast.node.statement import StatementNode
|
||||
# from smnp.ast.node.type import TypeNode
|
||||
# from smnp.ast.parser import Parser
|
||||
# from smnp.token.type import TokenType
|
||||
#
|
||||
#
|
||||
# class ExtendNode(StatementNode):
|
||||
# def __init__(self, pos):
|
||||
# super().__init__(pos)
|
||||
# self.children = [NoneNode(), NoneNode(), NoneNode()]
|
||||
#
|
||||
# @property
|
||||
# def type(self):
|
||||
# return self[0]
|
||||
#
|
||||
# @type.setter
|
||||
# def type(self, value):
|
||||
# self[0] = value
|
||||
#
|
||||
# @property
|
||||
# def variable(self):
|
||||
# return self[1]
|
||||
#
|
||||
# @variable.setter
|
||||
# def variable(self, value):
|
||||
# self[1] = value
|
||||
#
|
||||
# @property
|
||||
# def methods(self):
|
||||
# return self[2]
|
||||
#
|
||||
# @methods.setter
|
||||
# def methods(self, value):
|
||||
# self[2] = value
|
||||
#
|
||||
# @classmethod
|
||||
# def _parse(cls, input):
|
||||
# def createNode(extend, type, asKeyword, variable, methods):
|
||||
# node = ExtendNode(extend.pos)
|
||||
# node.type = type
|
||||
# node.variable = variable
|
||||
# node.methods = methods
|
||||
# return node
|
||||
#
|
||||
# return Parser.allOf(
|
||||
# Parser.terminalParser(TokenType.EXTEND),
|
||||
# Parser.doAssert(TypeNode.parse, "type being extended"),
|
||||
# Parser.terminalParser(TokenType.AS, doAssert=True),
|
||||
# Parser.doAssert(IdentifierNode.identifierParser(), "variable name"),
|
||||
# Parser.doAssert(cls._methodsDeclarationsParser(), "methods declarations"),
|
||||
# createNode=createNode
|
||||
# )(input)
|
||||
#
|
||||
# @classmethod
|
||||
# def _methodsDeclarationsParser(cls):
|
||||
# def createNode(openBracket, items, closeBracket):
|
||||
# node = BlockNode(openBracket.pos)
|
||||
# node.children = items
|
||||
# return node
|
||||
#
|
||||
# return Parser.loop(
|
||||
# Parser.terminalParser(TokenType.OPEN_CURLY),
|
||||
# Parser.doAssert(FunctionDefinitionNode.parse, f"method declaration or '{TokenType.CLOSE_CURLY.key}'"),
|
||||
# Parser.terminalParser(TokenType.CLOSE_CURLY),
|
||||
# createNode=createNode
|
||||
# )
|
||||
@@ -1,34 +1,64 @@
|
||||
from smnp.ast.node.chain import ChainParser
|
||||
from smnp.ast.node.operator import BinaryOperator, Operator, UnaryOperator
|
||||
from smnp.ast.node.unit import UnitParser
|
||||
from smnp.ast.node.valuable import Valuable
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class Factor(Valuable):
|
||||
pass
|
||||
|
||||
|
||||
class NotOperator(UnaryOperator):
|
||||
pass
|
||||
|
||||
|
||||
class Power(BinaryOperator):
|
||||
class Loop(BinaryOperator):
|
||||
pass
|
||||
|
||||
|
||||
def FactorParser(input):
|
||||
from smnp.ast.node.expression import MaxPrecedenceExpressionParser
|
||||
from smnp.ast.node.statement import StatementParser
|
||||
|
||||
powerFactor = Parser.leftAssociativeOperatorParser(
|
||||
UnitParser,
|
||||
ChainParser,
|
||||
[TokenType.DOUBLE_ASTERISK],
|
||||
UnitParser,
|
||||
lambda left, op, right: Power.withValues(left, op, right),
|
||||
ChainParser,
|
||||
lambda left, op, right: Factor.withValue(BinaryOperator.withValues(left, op, right)),
|
||||
name="power operator"
|
||||
)
|
||||
|
||||
notOperator = Parser.allOf(
|
||||
Parser.terminal(TokenType.NOT, Operator.withValue),
|
||||
exprFactor = Parser.allOf(
|
||||
Parser.terminalParser(TokenType.OPEN_PAREN),
|
||||
MaxPrecedenceExpressionParser,
|
||||
Parser.terminalParser(TokenType.CLOSE_PAREN),
|
||||
createNode=lambda open, expr, close: expr,
|
||||
name="grouping parentheses"
|
||||
)
|
||||
|
||||
factorParser = Parser.oneOf(
|
||||
powerFactor,
|
||||
exprFactor,
|
||||
name="basic factor"
|
||||
)
|
||||
|
||||
notOperator = Parser.allOf(
|
||||
Parser.terminalParser(TokenType.NOT, Operator.withValue),
|
||||
factorParser,
|
||||
createNode=NotOperator.withValues,
|
||||
name="not"
|
||||
)
|
||||
|
||||
loopFactor = Parser.allOf(
|
||||
factorParser,
|
||||
Parser.terminalParser(TokenType.DASH, createNode=Operator.withValue),
|
||||
StatementParser,
|
||||
createNode=Loop.withValues,
|
||||
name="dash-loop"
|
||||
)
|
||||
|
||||
return Parser.oneOf(
|
||||
loopFactor,
|
||||
notOperator,
|
||||
powerFactor,
|
||||
name="factor"
|
||||
factorParser
|
||||
)(input)
|
||||
|
||||
@@ -1,165 +1,128 @@
|
||||
from smnp.ast.node.block import BlockParser
|
||||
from smnp.ast.node.expression import ExpressionParser
|
||||
from smnp.ast.node.identifier import IdentifierLiteralParser
|
||||
from smnp.ast.node.iterable import abstractIterableParser
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.node.none import NoneNode
|
||||
from smnp.ast.node.type import TypeParser, Type
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class ArgumentsDeclaration(Node):
|
||||
pass
|
||||
|
||||
|
||||
class Argument(Node):
|
||||
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
self.children = [NoneNode(), NoneNode(), False, NoneNode()]
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self[0]
|
||||
|
||||
|
||||
@type.setter
|
||||
def type(self, value):
|
||||
self[0] = value
|
||||
|
||||
|
||||
@property
|
||||
def variable(self):
|
||||
return self[1]
|
||||
|
||||
|
||||
@variable.setter
|
||||
def variable(self, value):
|
||||
self[1] = value
|
||||
|
||||
|
||||
@property
|
||||
def vararg(self):
|
||||
return self[2]
|
||||
|
||||
|
||||
@vararg.setter
|
||||
def vararg(self, value):
|
||||
self[2] = value
|
||||
|
||||
|
||||
@property
|
||||
def optionalValue(self):
|
||||
return self[3]
|
||||
|
||||
@optionalValue.setter
|
||||
def optionalValue(self, value):
|
||||
self[3] = value
|
||||
|
||||
class VarargNode(Node):
|
||||
pass
|
||||
|
||||
|
||||
class FunctionDefinition(Node):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
self.children = [NoneNode(), NoneNode(), NoneNode()]
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self[0]
|
||||
|
||||
@name.setter
|
||||
def name(self, value):
|
||||
self[0] = value
|
||||
|
||||
@property
|
||||
def arguments(self):
|
||||
return self[1]
|
||||
|
||||
@arguments.setter
|
||||
def arguments(self, value):
|
||||
self[1] = value
|
||||
|
||||
@property
|
||||
def body(self):
|
||||
return self[2]
|
||||
|
||||
@body.setter
|
||||
def body(self, value):
|
||||
self[2] = value
|
||||
|
||||
@classmethod
|
||||
def withValues(cls, name, arguments, body):
|
||||
node = cls(name.pos)
|
||||
node.name = name
|
||||
node.arguments = arguments
|
||||
node.body = body
|
||||
return node
|
||||
|
||||
|
||||
def RegularArgumentParser(input):
|
||||
def createNode(type, variable, vararg):
|
||||
pos = type.pos if isinstance(type, Type) else variable.pos
|
||||
node = Argument(pos)
|
||||
node.type = type
|
||||
node.variable = variable
|
||||
node.vararg = vararg is True
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.optional(TypeParser),
|
||||
Parser.doAssert(IdentifierLiteralParser, "argument name"),
|
||||
Parser.optional(Parser.terminal(TokenType.DOTS, lambda val, pos: True)),
|
||||
createNode=createNode,
|
||||
name="regular function argument"
|
||||
)(input)
|
||||
|
||||
|
||||
def OptionalArgumentParser(input):
|
||||
def createNode(type, variable, _, optional):
|
||||
pos = type.pos if isinstance(type, Type) else variable.pos
|
||||
node = Argument(pos)
|
||||
node.type = type
|
||||
node.variable = variable
|
||||
node.optionalValue = optional
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.optional(TypeParser),
|
||||
Parser.doAssert(IdentifierLiteralParser, "argument name"),
|
||||
Parser.terminal(TokenType.ASSIGN),
|
||||
Parser.doAssert(ExpressionParser, "expression"),
|
||||
createNode=createNode,
|
||||
name="optional function argument"
|
||||
)(input)
|
||||
|
||||
|
||||
def ArgumentParser(input):
|
||||
return Parser.oneOf(
|
||||
OptionalArgumentParser,
|
||||
RegularArgumentParser,
|
||||
name="function argument"
|
||||
)(input)
|
||||
|
||||
|
||||
def ArgumentsDeclarationParser(input):
|
||||
return abstractIterableParser(
|
||||
ArgumentsDeclaration,
|
||||
TokenType.OPEN_PAREN,
|
||||
TokenType.CLOSE_PAREN,
|
||||
Parser.doAssert(ArgumentParser, "function/method argument")
|
||||
)(input)
|
||||
|
||||
|
||||
def FunctionDefinitionParser(input):
|
||||
return Parser.allOf(
|
||||
Parser.terminal(TokenType.FUNCTION),
|
||||
Parser.doAssert(IdentifierLiteralParser, "function/method name"),
|
||||
Parser.doAssert(ArgumentsDeclarationParser, "function/method arguments"),
|
||||
Parser.doAssert(BlockParser, "function/method body"),
|
||||
createNode=lambda _, name, args, body: FunctionDefinition.withValues(name, args, body),
|
||||
name="function definition"
|
||||
)(input)
|
||||
|
||||
# from smnp.ast.node.block import BlockNode
|
||||
# from smnp.ast.node.expression import ExpressionNode
|
||||
# from smnp.ast.node.identifier import IdentifierNode
|
||||
# from smnp.ast.node.iterable import abstractIterableParser
|
||||
# from smnp.ast.node.model import Node
|
||||
# from smnp.ast.node.none import NoneNode
|
||||
# from smnp.ast.node.statement import StatementNode
|
||||
# from smnp.ast.node.type import TypeNode, TypeSpecifier
|
||||
# from smnp.ast.parser import Parser
|
||||
# from smnp.token.type import TokenType
|
||||
#
|
||||
#
|
||||
# class ArgumentsDeclarationNode(Node):
|
||||
#
|
||||
# @classmethod
|
||||
# def _parse(cls, input):
|
||||
# raise RuntimeError("This class is not supposed to be automatically called")
|
||||
#
|
||||
#
|
||||
# class VarargNode(Node):
|
||||
# pass
|
||||
#
|
||||
#
|
||||
# class ArgumentDefinitionNode(ExpressionNode):
|
||||
# def __init__(self, pos):
|
||||
# super().__init__(pos)
|
||||
# self.children.extend([NoneNode(), False])
|
||||
#
|
||||
# @property
|
||||
# def type(self):
|
||||
# return self[0]
|
||||
#
|
||||
# @type.setter
|
||||
# def type(self, value):
|
||||
# self[0] = value
|
||||
#
|
||||
# @property
|
||||
# def variable(self):
|
||||
# return self[1]
|
||||
#
|
||||
# @variable.setter
|
||||
# def variable(self, value):
|
||||
# self[1] = value
|
||||
#
|
||||
# @property
|
||||
# def vararg(self):
|
||||
# return self[2]
|
||||
#
|
||||
# @vararg.setter
|
||||
# def vararg(self, value):
|
||||
# self[2] = value
|
||||
#
|
||||
#
|
||||
# @classmethod
|
||||
# def parser(cls):
|
||||
# def createNode(type, variable, dots):
|
||||
# node = ArgumentDefinitionNode(type.pos)
|
||||
# node.type = type
|
||||
# node.variable = variable
|
||||
# node.vararg = isinstance(dots, VarargNode)
|
||||
# return node
|
||||
#
|
||||
# return Parser.allOf(
|
||||
# Parser.optional(Parser.oneOf(
|
||||
# TypeNode.parse,
|
||||
# TypeSpecifier.parse
|
||||
# )),
|
||||
# Parser.doAssert(IdentifierNode.identifierParser(), "variable name"),
|
||||
# Parser.optional(Parser.terminalParser(TokenType.DOTS, lambda val, pos: VarargNode(pos))),
|
||||
# createNode=createNode
|
||||
# )
|
||||
#
|
||||
# @classmethod
|
||||
# def _parse(cls, input):
|
||||
# #TODO
|
||||
# raise RuntimeError("Not implemented yet. There is still required work to correctly build AST related to IdentifierNode")
|
||||
#
|
||||
#
|
||||
#
|
||||
# class FunctionDefinitionNode(StatementNode):
|
||||
# def __init__(self, pos):
|
||||
# super().__init__(pos)
|
||||
# self.children = [NoneNode(), NoneNode(), NoneNode()]
|
||||
#
|
||||
# @property
|
||||
# def name(self):
|
||||
# return self[0]
|
||||
#
|
||||
# @name.setter
|
||||
# def name(self, value):
|
||||
# self[0] = value
|
||||
#
|
||||
# @property
|
||||
# def arguments(self):
|
||||
# return self[1]
|
||||
#
|
||||
# @arguments.setter
|
||||
# def arguments(self, value):
|
||||
# self[1] = value
|
||||
#
|
||||
# @property
|
||||
# def body(self):
|
||||
# return self[2]
|
||||
#
|
||||
# @body.setter
|
||||
# def body(self, value):
|
||||
# self[2] = value
|
||||
#
|
||||
# @classmethod
|
||||
# def _parse(cls, input):
|
||||
# def createNode(function, name, arguments, body):
|
||||
# node = FunctionDefinitionNode(function.pos)
|
||||
# node.name = name
|
||||
# node.arguments = arguments
|
||||
# node.body = body
|
||||
# return node
|
||||
#
|
||||
# return Parser.allOf(
|
||||
# Parser.terminalParser(TokenType.FUNCTION),
|
||||
# Parser.doAssert(IdentifierNode.identifierParser(), "function name"),
|
||||
# Parser.doAssert(cls._argumentsDeclarationParser(), "arguments list"),
|
||||
# Parser.doAssert(BlockNode.parse, "function body"),
|
||||
# createNode=createNode
|
||||
# )(input)
|
||||
#
|
||||
# @staticmethod
|
||||
# def _argumentsDeclarationParser():
|
||||
# return abstractIterableParser(ArgumentsDeclarationNode, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, ArgumentDefinitionNode.parser())
|
||||
@@ -1,11 +1,10 @@
|
||||
from smnp.ast.node.atom import Atom
|
||||
from smnp.ast.node.expression import ExpressionParser
|
||||
from smnp.ast.node.iterable import abstractIterableParser
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.node.none import NoneNode
|
||||
from smnp.ast.node.operator import BinaryOperator, Operator
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.ast.parser import Parsers
|
||||
from smnp.token.type import TokenType
|
||||
from smnp.util.singleton import SingletonParser
|
||||
|
||||
|
||||
class Identifier(Atom):
|
||||
@@ -49,26 +48,28 @@ class Assignment(BinaryOperator):
|
||||
pass
|
||||
|
||||
|
||||
def IdentifierLiteralParser(input):
|
||||
return Parser.terminal(TokenType.IDENTIFIER, createNode=Identifier.withValue)(input)
|
||||
@SingletonParser
|
||||
def IdentifierParser():
|
||||
identifierLiteralParser = Parsers.terminal(TokenType.IDENTIFIER, createNode=Identifier.withValue)
|
||||
|
||||
|
||||
def IdentifierParser(input):
|
||||
functionCallParser = Parser.allOf(
|
||||
IdentifierLiteralParser,
|
||||
abstractIterableParser(ArgumentsList, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, Parser.doAssert(ExpressionParser, "expression")),
|
||||
createNode=lambda name, arguments: FunctionCall.withChildren(name, arguments)
|
||||
functionCallParser = Parsers.allOf(
|
||||
identifierLiteralParser,
|
||||
#abstractIterableParser(ArgumentsList, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, MaxPrecedenceExpressionParser),
|
||||
createNode=lambda name, arguments: FunctionCall.withChildren(name, arguments),
|
||||
name="functionCall"
|
||||
)
|
||||
|
||||
assignmentParser = Parser.allOf(
|
||||
IdentifierLiteralParser,
|
||||
Parser.terminal(TokenType.ASSIGN, createNode=Operator.withValue),
|
||||
Parser.doAssert(ExpressionParser, "expression"),
|
||||
createNode=lambda identifier, assign, expr: Assignment.withValues(identifier, assign, expr)
|
||||
assignmentParser = Parsers.allOf(
|
||||
identifierLiteralParser,
|
||||
Parsers.terminal(TokenType.ASSIGN, createNode=Operator.withValue),
|
||||
#MaxPrecedenceExpressionParser,
|
||||
createNode=lambda identifier, assign, expr: Assignment.withValues(identifier, assign, expr),
|
||||
name="assignment"
|
||||
)
|
||||
|
||||
return Parser.oneOf(
|
||||
return Parsers.oneOf(
|
||||
assignmentParser,
|
||||
functionCallParser,
|
||||
IdentifierLiteralParser
|
||||
)(input)
|
||||
identifierLiteralParser,
|
||||
name="idExpr"
|
||||
)
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
# from smnp.ast.node.identifier import Identifier
|
||||
# from smnp.ast.node.model import Node
|
||||
# from smnp.ast.node.none import NoneNode
|
||||
# from smnp.ast.node.string import StringLiteralNode
|
||||
# from smnp.ast.node.type import TypeNode
|
||||
# from smnp.ast.parser import Parser
|
||||
# from smnp.token.type import TokenType
|
||||
#
|
||||
from smnp.ast.node.atom import StringParser
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.parser import Parser
|
||||
@@ -26,8 +34,8 @@ class Import(Node):
|
||||
|
||||
def ImportParser(input):
|
||||
return Parser.allOf(
|
||||
Parser.terminal(TokenType.IMPORT),
|
||||
Parser.doAssert(StringParser, "import source as string"),
|
||||
Parser.terminalParser(TokenType.IMPORT),
|
||||
StringParser,
|
||||
createNode=lambda imp, source: Import.withValue(source),
|
||||
name="import"
|
||||
)(input)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
from smnp.ast.node.ignore import IgnoredNode
|
||||
from smnp.ast.node.model import Node, ParseResult
|
||||
from smnp.ast.node.none import NoneNode
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.ast.parser import Parsers, DecoratorParser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, itemParser):
|
||||
def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, itemParser, name):
|
||||
|
||||
class AbstractIterable(Node):
|
||||
def __init__(self, pos):
|
||||
@@ -31,70 +31,74 @@ def abstractIterableParser(iterableNodeType, openTokenType, closeTokenType, item
|
||||
class AbstractIterableTail(AbstractIterable):
|
||||
pass
|
||||
|
||||
def abstractIterableParser(input):
|
||||
return Parser.oneOf(
|
||||
emptyIterable,
|
||||
openIterable
|
||||
)(input)
|
||||
def abstractIterableParser():
|
||||
return Parsers.oneOf(
|
||||
emptyIterable(),
|
||||
openIterable(),
|
||||
name=name
|
||||
)
|
||||
|
||||
def emptyIterable(input):
|
||||
def emptyIterable():
|
||||
def createNode(open, close):
|
||||
node = AbstractIterable(open.pos)
|
||||
node.value = open
|
||||
node.next = close
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.terminal(openTokenType),
|
||||
Parser.terminal(closeTokenType),
|
||||
createNode=createNode
|
||||
)(input)
|
||||
return Parsers.allOf(
|
||||
Parsers.terminal(openTokenType),
|
||||
Parsers.terminal(closeTokenType),
|
||||
createNode=createNode,
|
||||
name=name+"Empty"
|
||||
)
|
||||
|
||||
def openIterable(input):
|
||||
def openIterable():
|
||||
def createNode(open, item, tail):
|
||||
node = AbstractIterable(open.pos)
|
||||
node.value = item
|
||||
node.next = tail
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.terminal(openTokenType),
|
||||
return Parsers.allOf(
|
||||
Parsers.terminal(openTokenType),
|
||||
itemParser,
|
||||
abstractIterableTailParser,
|
||||
createNode=createNode
|
||||
)(input)
|
||||
abstractIterableTailParser(),
|
||||
createNode=createNode,
|
||||
name=name+"Open"
|
||||
)
|
||||
|
||||
def abstractIterableTailParser(input):
|
||||
return Parser.oneOf(
|
||||
closeIterable,
|
||||
nextItem,
|
||||
)(input)
|
||||
def abstractIterableTailParser():
|
||||
return Parsers.oneOf(
|
||||
closeIterable(),
|
||||
nextItem(),
|
||||
name=name+"Tail"
|
||||
)
|
||||
|
||||
def nextItem(input):
|
||||
def nextItem():
|
||||
def createNode(comma, item, tail):
|
||||
node = AbstractIterableTail(item.pos)
|
||||
node.value = item
|
||||
node.next = tail
|
||||
return node
|
||||
|
||||
return Parser.allOf(
|
||||
Parser.doAssert(Parser.terminal(TokenType.COMMA), f"'{TokenType.COMMA.key}' or '{closeTokenType.key}'"),
|
||||
return Parsers.allOf(
|
||||
Parsers.terminal(TokenType.COMMA, doAssert=True),
|
||||
itemParser,
|
||||
abstractIterableTailParser,
|
||||
abstractIterableTailParser(),
|
||||
name=name+"NextItem",
|
||||
createNode=createNode
|
||||
)(input)
|
||||
)
|
||||
|
||||
def closeIterable(input):
|
||||
return Parser.terminal(closeTokenType)(input)
|
||||
def closeIterable():
|
||||
return Parsers.terminal(closeTokenType)
|
||||
|
||||
|
||||
return toFlatDesiredNode(iterableNodeType, abstractIterableParser)
|
||||
return abstractIterableParser()
|
||||
#return toFlatDesiredNode(iterableNodeType, abstractIterableParser())
|
||||
|
||||
|
||||
def toFlatDesiredNode(iterableNodeType, parser):
|
||||
def parse(input):
|
||||
result = parser(input)
|
||||
|
||||
def wrapper(result):
|
||||
if result.result:
|
||||
value = flattenList(result.node)
|
||||
node = iterableNodeType(result.node.pos)
|
||||
@@ -105,7 +109,7 @@ def toFlatDesiredNode(iterableNodeType, parser):
|
||||
|
||||
return ParseResult.FAIL()
|
||||
|
||||
return Parser(parse, "flat", [parser])
|
||||
return DecoratorParser(wrapper, parser)
|
||||
|
||||
|
||||
def flattenList(node, output=None):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from smnp.ast.node.atom import AtomParser
|
||||
from smnp.ast.node.iterable import abstractIterableParser
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
@@ -8,12 +8,6 @@ class List(Node):
|
||||
pass
|
||||
|
||||
|
||||
def ListParser(input):
|
||||
from smnp.ast.node.expression import ExpressionParser
|
||||
|
||||
return abstractIterableParser(
|
||||
List,
|
||||
TokenType.OPEN_SQUARE,
|
||||
TokenType.CLOSE_SQUARE,
|
||||
Parser.doAssert(ExpressionParser, "expression")
|
||||
)(input)
|
||||
def ListParser():
|
||||
return abstractIterableParser(List, TokenType.OPEN_SQUARE, TokenType.CLOSE_SQUARE, AtomParser(), name="list")
|
||||
#MaxPrecedenceExpressionParser)(input)
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
from smnp.ast.node.atom import LiteralParser
|
||||
from smnp.ast.node.identifier import IdentifierLiteralParser
|
||||
from smnp.ast.node.iterable import abstractIterableParser
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.node.operator import BinaryOperator, Operator
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.ast.parser import Parsers
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
@@ -31,24 +29,19 @@ class Map(Node):
|
||||
|
||||
|
||||
def MapParser(input):
|
||||
from smnp.ast.node.expression import ExpressionParser
|
||||
keyParser = Parser.oneOf(
|
||||
LiteralParser,
|
||||
IdentifierLiteralParser
|
||||
)
|
||||
valueParser = ExpressionParser
|
||||
from smnp.ast.node.atom import LiteralParser
|
||||
#from smnp.ast.node.expression import MaxPrecedenceExpressionParser
|
||||
keyParser = LiteralParser
|
||||
#valueParser = MaxPrecedenceExpressionParser
|
||||
|
||||
mapEntryParser = Parser.allOf(
|
||||
mapEntryParser = Parsers.allOf(
|
||||
keyParser,
|
||||
Parser.terminal(TokenType.ARROW, createNode=Operator.withValue),
|
||||
Parser.doAssert(valueParser, "expression"),
|
||||
createNode=MapEntry.withValues
|
||||
Parsers.terminal(TokenType.ARROW, createNode=Operator.withValue),
|
||||
#valueParser,
|
||||
createNode=MapEntry.withValues,
|
||||
name="mapEntry"
|
||||
)
|
||||
|
||||
return abstractIterableParser(
|
||||
Map,
|
||||
TokenType.OPEN_CURLY,
|
||||
TokenType.CLOSE_CURLY,
|
||||
mapEntryParser
|
||||
)(input)
|
||||
return abstractIterableParser(Map, TokenType.OPEN_CURLY, TokenType.CLOSE_CURLY, mapEntryParser)
|
||||
|
||||
|
||||
|
||||
@@ -28,6 +28,21 @@ class Node:
|
||||
def pop(self, index):
|
||||
return self.children.pop(index)
|
||||
|
||||
@classmethod
|
||||
def _parse(cls, input):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def parse(cls, input):
|
||||
result = cls._parse(input)
|
||||
if result is None:
|
||||
return ParseResult.FAIL()
|
||||
|
||||
if not isinstance(result, ParseResult):
|
||||
raise RuntimeError(f"_parse() method of '{cls.__name__}' class haven't returned ParseResult object")
|
||||
|
||||
return result
|
||||
|
||||
def print(self):
|
||||
self._print(first=True)
|
||||
|
||||
|
||||
@@ -68,7 +68,68 @@ class BinaryOperator(Node):
|
||||
node.right = right
|
||||
return node
|
||||
|
||||
|
||||
#
|
||||
# class LeftAssociativeOperatorNode(ExpressionNode):
|
||||
# def __init__(self, pos):
|
||||
# super().__init__(pos)
|
||||
# self.children = [NoneNode(), NoneNode(), NoneNode()]
|
||||
#
|
||||
# @property
|
||||
# def left(self):
|
||||
# return self[0]
|
||||
#
|
||||
# @left.setter
|
||||
# def left(self, value):
|
||||
# self[0] = value
|
||||
#
|
||||
# @property
|
||||
# def operator(self):
|
||||
# return self[1]
|
||||
#
|
||||
# @operator.setter
|
||||
# def operator(self, value):
|
||||
# self[1] = value
|
||||
#
|
||||
# @property
|
||||
# def right(self):
|
||||
# return self[2]
|
||||
#
|
||||
# @right.setter
|
||||
# def right(self, value):
|
||||
# self[2] = value
|
||||
#
|
||||
# @classmethod
|
||||
# def _parse(cls, input):
|
||||
# def createNode(left, operator, right):
|
||||
# node = LeftAssociativeOperatorNode(right.pos)
|
||||
# node.left = left
|
||||
# node.operator = operator
|
||||
# node.right = right
|
||||
# return node
|
||||
#
|
||||
# return Parser.leftAssociativeOperatorParser(
|
||||
# cls._lhsParser(),
|
||||
# TokenType.DOT,
|
||||
# cls._rhsParser(),
|
||||
# createNode=createNode
|
||||
# )(input)
|
||||
#
|
||||
# @classmethod
|
||||
# def _lhsParser(cls):
|
||||
# raise RuntimeError(f"LHS parser is not implemented in {cls.__name__}")
|
||||
#
|
||||
# @staticmethod
|
||||
# def _rhsParser():
|
||||
# from smnp.ast.node.identifier import IdentifierNode
|
||||
#
|
||||
# return Parser.oneOf(
|
||||
# # TODO!!!
|
||||
# IdentifierNode._lhsParser(),
|
||||
# IdentifierNode._functionCallParser(),
|
||||
# exception=lambda input: SyntaxException(f"Expected property name or method call, found '{input.current().rawValue}'", input.currentPos())
|
||||
# )
|
||||
#
|
||||
#
|
||||
class Operator(Node):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
|
||||
@@ -1,36 +1,44 @@
|
||||
from smnp.ast.node.extend import ExtendParser
|
||||
from smnp.ast.node.function import FunctionDefinitionParser
|
||||
from smnp.ast.node.imports import ImportParser
|
||||
from smnp.ast.node.model import Node, ParseResult
|
||||
from smnp.ast.node.statement import StatementParser
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.error.syntax import SyntaxException
|
||||
|
||||
|
||||
class Program(Node):
|
||||
def __init__(self):
|
||||
super().__init__((-1, -1))
|
||||
|
||||
def ProgramParser(input):
|
||||
def parse(input):
|
||||
root = Program()
|
||||
|
||||
# Start Symbol
|
||||
startSymbolParser = Parser.oneOf(
|
||||
def parse(input):
|
||||
root = Program()
|
||||
while input.hasCurrent():
|
||||
result = Parser.oneOf(
|
||||
# Start Symbol
|
||||
ImportParser,
|
||||
FunctionDefinitionParser,
|
||||
ExtendParser,
|
||||
StatementParser,
|
||||
exception=lambda inp: SyntaxException(f"Invalid statement: {inp.currentToEndOfLine()}", inp.current().pos),
|
||||
name="start symbol"
|
||||
)
|
||||
exception=RuntimeError("Nie znam tego wyrazenia")
|
||||
)(input)
|
||||
|
||||
while input.hasCurrent():
|
||||
result = startSymbolParser(input)
|
||||
if result.result:
|
||||
root.append(result.node)
|
||||
|
||||
if result.result:
|
||||
root.append(result.node)
|
||||
return ParseResult.OK(root)
|
||||
|
||||
return ParseResult.OK(root)
|
||||
|
||||
return Parser(parse, name="program")(input)
|
||||
ProgramParser = Parser(parse, name="program")
|
||||
# @classmethod
|
||||
# def _parse(cls, input):
|
||||
# def parseToken(input):
|
||||
# return Parser.oneOf(
|
||||
# FunctionDefinitionNode.parse,
|
||||
# ExtendNode.parse,
|
||||
# ExpressionNode.parse,
|
||||
# ImportNode.parse,
|
||||
# StatementNode.parse,
|
||||
# exception = SyntaxException(f"Invalid statement: {input.currentToEndOfLine()}", input.current().pos)
|
||||
# )(input)
|
||||
#
|
||||
# root = Program()
|
||||
# while input.hasCurrent():
|
||||
# result = parseToken(input)
|
||||
# if result.result:
|
||||
# root.append(result.node)
|
||||
# return ParseResult.OK(root)
|
||||
@@ -1,17 +1,32 @@
|
||||
from smnp.ast.node.expression import ExpressionParser
|
||||
from smnp.ast.node.valuable import Valuable
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class Return(Valuable):
|
||||
pass
|
||||
|
||||
|
||||
def ReturnParser(input):
|
||||
return Parser.allOf(
|
||||
Parser.terminal(TokenType.RETURN),
|
||||
Parser.optional(ExpressionParser),
|
||||
createNode=lambda ret, val: Return.withValue(val, ret.pos),
|
||||
name="return"
|
||||
)(input)
|
||||
# from smnp.ast.node.expression import ExpressionNode
|
||||
# from smnp.ast.node.none import NoneNode
|
||||
# from smnp.ast.node.statement import StatementNode
|
||||
# from smnp.ast.parser import Parser
|
||||
# from smnp.token.type import TokenType
|
||||
#
|
||||
#
|
||||
# class ReturnNode(StatementNode):
|
||||
# def __init__(self, pos):
|
||||
# super().__init__(pos)
|
||||
# self.children.append(NoneNode())
|
||||
#
|
||||
# @property
|
||||
# def value(self):
|
||||
# return self[0]
|
||||
#
|
||||
# @value.setter
|
||||
# def value(self, value):
|
||||
# self[0] = value
|
||||
#
|
||||
# @classmethod
|
||||
# def _parse(cls, input):
|
||||
# def createNode(ret, value):
|
||||
# node = ReturnNode(ret.pos)
|
||||
# node.value = value
|
||||
# return node
|
||||
#
|
||||
# return Parser.allOf(
|
||||
# Parser.terminalParser(TokenType.RETURN),
|
||||
# Parser.doAssert(ExpressionNode.parse, "expression"),
|
||||
# createNode=createNode
|
||||
# )(input)
|
||||
@@ -1,6 +1,6 @@
|
||||
from smnp.ast.node.expression import MaxPrecedenceExpressionParser
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class Statement(Node):
|
||||
@@ -10,28 +10,25 @@ class Statement(Node):
|
||||
def StatementParser(input):
|
||||
from smnp.ast.node.block import BlockParser
|
||||
from smnp.ast.node.condition import IfElseStatementParser
|
||||
from smnp.ast.node.expression import ExpressionParser
|
||||
from smnp.ast.node.ret import ReturnParser
|
||||
from smnp.ast.node.throw import ThrowParser
|
||||
|
||||
return withSemicolon(
|
||||
Parser.oneOf(
|
||||
IfElseStatementParser,
|
||||
ExpressionParser, # Must be above BlockParser because of Map's syntax with curly braces
|
||||
BlockParser,
|
||||
ReturnParser,
|
||||
ThrowParser,
|
||||
name="statement"
|
||||
), optional=True)(input)
|
||||
|
||||
|
||||
def withSemicolon(parser, optional=False, doAssert=False):
|
||||
semicolonParser = Parser.optional(Parser.terminal(TokenType.SEMICOLON)) if optional else Parser.terminal(
|
||||
TokenType.SEMICOLON, doAssert=doAssert)
|
||||
|
||||
return Parser.allOf(
|
||||
parser,
|
||||
semicolonParser,
|
||||
createNode=lambda stmt, semicolon: stmt,
|
||||
name="semicolon" + "?" if optional else ""
|
||||
parser = Parser.oneOf(
|
||||
IfElseStatementParser,
|
||||
BlockParser,
|
||||
MaxPrecedenceExpressionParser
|
||||
)
|
||||
|
||||
return Parser(parser, "statement", parser)(input)
|
||||
|
||||
# class StatementNode(Node):
|
||||
#
|
||||
# @classmethod
|
||||
# def _parse(cls, input):
|
||||
# from smnp.ast.node.block import BlockNode
|
||||
# from smnp.ast.node.expression import ExpressionNode
|
||||
# from smnp.ast.node.ret import ReturnNode
|
||||
#
|
||||
# return Parser.oneOf(
|
||||
# ExpressionNode.parse,
|
||||
# BlockNode.parse,
|
||||
# ReturnNode.parse,
|
||||
# )(input)
|
||||
@@ -1,17 +1,12 @@
|
||||
from smnp.ast.node.factor import FactorParser
|
||||
from smnp.ast.node.operator import BinaryOperator
|
||||
from smnp.ast.node.valuable import Valuable
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class Product(BinaryOperator):
|
||||
class Term(Valuable):
|
||||
pass
|
||||
|
||||
|
||||
def TermParser(input):
|
||||
return Parser.leftAssociativeOperatorParser(
|
||||
FactorParser,
|
||||
[TokenType.ASTERISK, TokenType.SLASH],
|
||||
FactorParser,
|
||||
lambda left, op, right: Product.withValues(left, op, right)
|
||||
)(input)
|
||||
TermParser = Parser.leftAssociativeOperatorParser(FactorParser, [TokenType.ASTERISK, TokenType.SLASH], FactorParser,
|
||||
lambda left, op, right: Term.withValue(BinaryOperator.withValues(left, op, right)))
|
||||
@@ -1,17 +0,0 @@
|
||||
from smnp.ast.node.expression import ExpressionParser
|
||||
from smnp.ast.node.valuable import Valuable
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class Throw(Valuable):
|
||||
pass
|
||||
|
||||
|
||||
def ThrowParser(input):
|
||||
return Parser.allOf(
|
||||
Parser.terminal(TokenType.THROW),
|
||||
Parser.doAssert(ExpressionParser, "error message as string"),
|
||||
createNode=lambda throw, message: Throw.withValue(message, throw.pos),
|
||||
name="throw"
|
||||
)(input)
|
||||
@@ -1,67 +1,63 @@
|
||||
from smnp.ast.node.atom import TypeLiteralParser
|
||||
from smnp.ast.node.iterable import abstractIterableParser
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.node.none import NoneNode
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class Type(Node):
|
||||
def __init__(self, pos):
|
||||
super().__init__(pos)
|
||||
self.children = [NoneNode(), NoneNode()]
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self[0]
|
||||
|
||||
@type.setter
|
||||
def type(self, value):
|
||||
self[0] = value
|
||||
|
||||
@property
|
||||
def specifiers(self):
|
||||
return self[1]
|
||||
|
||||
@specifiers.setter
|
||||
def specifiers(self, value):
|
||||
self[1] = value
|
||||
|
||||
@classmethod
|
||||
def withValues(cls, pos, type, specifiers=NoneNode()):
|
||||
node = cls(pos)
|
||||
node.type = type
|
||||
node.specifiers = specifiers
|
||||
return node
|
||||
|
||||
|
||||
class TypesList(Node):
|
||||
pass
|
||||
|
||||
|
||||
def TypesListParser(input):
|
||||
return abstractIterableParser(
|
||||
TypesList,
|
||||
TokenType.OPEN_ANGLE,
|
||||
TokenType.CLOSE_ANGLE,
|
||||
TypeParser
|
||||
)(input)
|
||||
|
||||
|
||||
class TypeSpecifiers(Node):
|
||||
pass
|
||||
|
||||
|
||||
def TypeParser(input):
|
||||
typeWithSpecifier = Parser.allOf(
|
||||
TypeLiteralParser,
|
||||
Parser.many(TypesListParser, createNode=TypeSpecifiers.withChildren),
|
||||
createNode=lambda type, specifiers: Type.withValues(type.pos, type, specifiers),
|
||||
name="type with specifiers?"
|
||||
)
|
||||
|
||||
return Parser.oneOf(
|
||||
typeWithSpecifier,
|
||||
TypesListParser,
|
||||
name="mult. types or type with specifier"
|
||||
)(input)
|
||||
# from smnp.ast.node.iterable import abstractIterableParser
|
||||
# from smnp.ast.node.model import Node
|
||||
# from smnp.ast.node.operator import LeftAssociativeOperatorNode
|
||||
# from smnp.ast.parser import Parser
|
||||
# from smnp.token.type import TokenType
|
||||
# from smnp.type.model import Type
|
||||
#
|
||||
#
|
||||
# class TypeSpecifier(Node):
|
||||
#
|
||||
# @classmethod
|
||||
# def _parse(cls, input):
|
||||
# return abstractIterableParser(TypeSpecifier, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE,
|
||||
# Parser.doAssert(cls._specifierItem(), "type"))(input)
|
||||
#
|
||||
# @classmethod
|
||||
# def _specifierItem(cls):
|
||||
# return Parser.oneOf(
|
||||
# TypeNode.parse,
|
||||
# cls.parse
|
||||
# )
|
||||
#
|
||||
# class TypeSpecifiers(Node):
|
||||
# pass
|
||||
#
|
||||
#
|
||||
# class TypeNode(LeftAssociativeOperatorNode):
|
||||
# def __init__(self, pos):
|
||||
# super().__init__(pos)
|
||||
#
|
||||
# @property
|
||||
# def type(self):
|
||||
# return self[0]
|
||||
#
|
||||
# @type.setter
|
||||
# def type(self, value):
|
||||
# self[0] = value
|
||||
#
|
||||
# @property
|
||||
# def specifiers(self):
|
||||
# return self[1]
|
||||
#
|
||||
# @specifiers.setter
|
||||
# def specifiers(self, value):
|
||||
# self[1] = value
|
||||
#
|
||||
# @classmethod
|
||||
# def _parse(cls, input):
|
||||
# def createNode(type, specifiers):
|
||||
# node = TypeNode(type.pos)
|
||||
# node.type = Type[type.value.upper()]
|
||||
# node.specifiers = specifiers
|
||||
# return node
|
||||
#
|
||||
# return Parser.allOf(
|
||||
# cls._rawTypeParser(),
|
||||
# Parser.many(TypeSpecifier.parse, lambda specifiers, pos: TypeSpecifiers.withChildren(specifiers, pos)),
|
||||
# createNode=createNode
|
||||
# )(input)
|
||||
#
|
||||
# @classmethod
|
||||
# def _rawTypeParser(cls):
|
||||
# return Parser.terminalParser(TokenType.TYPE, lambda val, pos: TypeNode.withValue(val, pos))
|
||||
@@ -1,36 +0,0 @@
|
||||
from smnp.ast.node.atom import AtomParser
|
||||
from smnp.ast.node.operator import BinaryOperator, UnaryOperator, Operator
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class MinusOperator(UnaryOperator):
|
||||
pass
|
||||
|
||||
|
||||
class Access(BinaryOperator):
|
||||
pass
|
||||
|
||||
|
||||
def UnitParser(input):
|
||||
minusOperator = Parser.allOf(
|
||||
Parser.terminal(TokenType.MINUS, createNode=Operator.withValue),
|
||||
Parser.doAssert(AtomParser, "atom"),
|
||||
createNode=MinusOperator.withValues,
|
||||
name="minus"
|
||||
)
|
||||
|
||||
atom2 = Parser.oneOf(
|
||||
minusOperator,
|
||||
AtomParser,
|
||||
name="atom2"
|
||||
)
|
||||
|
||||
return Parser.leftAssociativeOperatorParser(
|
||||
atom2,
|
||||
[TokenType.DOT],
|
||||
Parser.doAssert(atom2, "atom"),
|
||||
createNode=lambda left, op, right: Access.withValues(left, op, right),
|
||||
name="unit"
|
||||
)(input)
|
||||
|
||||
@@ -16,7 +16,7 @@ class Valuable(Node):
|
||||
self[0] = value
|
||||
|
||||
@classmethod
|
||||
def withValue(cls, value, pos=None):
|
||||
node = cls(value.pos if pos is None else pos)
|
||||
def withValue(cls, value):
|
||||
node = cls(value.pos)
|
||||
node.value = value
|
||||
return node
|
||||
@@ -9,15 +9,8 @@ def parse(input):
|
||||
return ProgramParser(input).node
|
||||
|
||||
|
||||
class Parser:
|
||||
def __init__(self, parse, name=None, parsers=None):
|
||||
if parsers is None:
|
||||
parsers = []
|
||||
self.parsers = parsers
|
||||
|
||||
self._parse = parse
|
||||
if name is None:
|
||||
name = parse.__name__
|
||||
class Parser(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def parse(self, input):
|
||||
@@ -26,10 +19,27 @@ class Parser:
|
||||
return ParseResult.FAIL()
|
||||
|
||||
if not isinstance(result, ParseResult):
|
||||
raise RuntimeError(f"_parse() method of '{self.__class__.__name__}' class haven't returned ParseResult object")
|
||||
raise RuntimeError(
|
||||
f"_parse() method of '{self.__class__.__name__}' class haven't returned ParseResult object")
|
||||
|
||||
return result
|
||||
|
||||
def _parse(self, input):
|
||||
raise RuntimeError(f"_name method of '{self.__class__.__name__}' class is not implemented")
|
||||
|
||||
def grammar(self):
|
||||
rules = []
|
||||
self._grammarRules(rules)
|
||||
return "\n".join(self._uniq(rules))
|
||||
|
||||
def _uniq(self, seq):
|
||||
seen = set()
|
||||
seen_add = seen.add
|
||||
return [x for x in seq if not (x in seen or seen_add(x))]
|
||||
|
||||
def _grammarRules(self, output):
|
||||
output.append(f"class '{self.__class__.__name__}' does not implement _grammarRules() method")
|
||||
|
||||
def __call__(self, input):
|
||||
return self.parse(input)
|
||||
|
||||
@@ -39,186 +49,242 @@ class Parser:
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
# a -> A
|
||||
|
||||
class Parsers:
|
||||
|
||||
@staticmethod
|
||||
def terminal(expectedType, createNode=None, doAssert=False):
|
||||
def provideNode(value, pos):
|
||||
if createNode is None:
|
||||
return IgnoredNode(pos)
|
||||
return createNode(value, pos)
|
||||
def terminal(expectedType, createNode=lambda val, pos: IgnoredNode(pos), doAssert=False):
|
||||
return TerminalParser(expectedType, createNode, doAssert)
|
||||
|
||||
def parse(input):
|
||||
if input.hasCurrent() and input.current().type == expectedType:
|
||||
token = input.current()
|
||||
input.ahead()
|
||||
return ParseResult.OK(provideNode(token.value, token.pos))
|
||||
elif doAssert:
|
||||
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ""
|
||||
raise SyntaxException(f"Expected '{expectedType.key}'{found}", input.currentPos())
|
||||
|
||||
return ParseResult.FAIL()
|
||||
|
||||
return Parser(parse, name=expectedType.name.lower())
|
||||
|
||||
# oneOf -> a | b | c | ...
|
||||
@staticmethod
|
||||
def oneOf(*parsers, assertExpected=None, exception=None, name="or"):
|
||||
def combinedParser(input):
|
||||
snap = input.snapshot()
|
||||
for parser in parsers:
|
||||
value = parser(input)
|
||||
if value.result:
|
||||
return value
|
||||
input.reset(snap)
|
||||
def oneOf(*parsers, name, exception=None):
|
||||
return OneOfParser(*parsers, name=name, exception=exception)
|
||||
|
||||
if assertExpected is not None:
|
||||
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ""
|
||||
raise SyntaxException(f"Expected {assertExpected}{found}", input.currentPos())
|
||||
|
||||
if exception is not None:
|
||||
if callable(exception):
|
||||
raise exception(input)
|
||||
else:
|
||||
raise exception
|
||||
|
||||
input.reset(snap)
|
||||
return ParseResult.FAIL()
|
||||
|
||||
return Parser(combinedParser, name=name, parsers=parsers)
|
||||
|
||||
# allOf -> a b c ...
|
||||
@staticmethod
|
||||
def allOf(*parsers, createNode, exception=None, name="all"):
|
||||
def allOf(*parsers, createNode, exception=None, name):
|
||||
return AllOfParser(*parsers, createNode=createNode, exception=exception, name=name)
|
||||
|
||||
@staticmethod
|
||||
def leftAssociativeOperatorParser(leftParser, operatorTokenTypes, rightParser, createNode, name):
|
||||
return LeftAssociativeOperatorParser(leftParser, operatorTokenTypes, rightParser, createNode, name)
|
||||
|
||||
@staticmethod
|
||||
def many(itemParser, createNode, name):
|
||||
return ManyParser(itemParser, createNode, name)
|
||||
|
||||
@staticmethod
|
||||
def optional(parser, name):
|
||||
return OptionalParser(parser, name)
|
||||
|
||||
@staticmethod
|
||||
def loop(startParser, itemParser, endParser, createNode, name):
|
||||
return LoopParser(startParser, itemParser, endParser, createNode, name)
|
||||
|
||||
|
||||
class DecoratorParser(Parser):
|
||||
def __init__(self, wrapper, parser):
|
||||
super().__init__(parser.name)
|
||||
self.wrapper = wrapper
|
||||
self.parser = parser
|
||||
self._grammarRules = parser._grammarRules
|
||||
|
||||
def _parse(self, input):
|
||||
result = self.parser.parse(input)
|
||||
return self.wrapper(result)
|
||||
|
||||
|
||||
class TerminalParser(Parser):
|
||||
|
||||
def __init__(self, expectedType, createNode=lambda val, pos: IgnoredNode(pos), doAssert=False):
|
||||
super().__init__(expectedType.name.lower())
|
||||
self.expectedType = expectedType
|
||||
self.createNode = createNode
|
||||
self.doAssert = doAssert
|
||||
|
||||
def _grammarRules(self, output):
|
||||
output.append(f"{self.name} -> '{self.expectedType.value}'")
|
||||
|
||||
def _parse(self, input):
|
||||
if input.isCurrent(self.expectedType):
|
||||
token = input.current()
|
||||
input.ahead()
|
||||
return ParseResult.OK(self.createNode(token.value, token.pos))
|
||||
elif self.doAssert:
|
||||
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ""
|
||||
raise SyntaxException(f"Expected '{self.expectedType.key}'{found}", input.currentPos())
|
||||
|
||||
return ParseResult.FAIL()
|
||||
|
||||
|
||||
|
||||
class OneOfParser(Parser):
|
||||
def __init__(self, *parsers, name, exception=None):
|
||||
super().__init__(name)
|
||||
self.parsers = parsers
|
||||
self.exception = exception
|
||||
|
||||
def _parse(self, input):
|
||||
snap = input.snapshot()
|
||||
for parser in self.parsers:
|
||||
value = parser.parse(input)
|
||||
if value.result:
|
||||
return value
|
||||
input.reset(snap) # TODO sprawdzic, czy koneiczne !!!!!
|
||||
|
||||
if self.exception is not None:
|
||||
if callable(self.exception):
|
||||
raise self.exception(input)
|
||||
else:
|
||||
raise self.exception
|
||||
|
||||
return ParseResult.FAIL()
|
||||
|
||||
def _grammarRules(self, output):
|
||||
output.extend([ f"{self.name} -> {parser.name}" for parser in self.parsers ])
|
||||
[ parser._grammarRules(output) for parser in self.parsers ]
|
||||
|
||||
|
||||
class AllOfParser(Parser):
|
||||
def __init__(self, *parsers, createNode, exception=None, name):
|
||||
super().__init__(name)
|
||||
|
||||
if len(parsers) == 0:
|
||||
raise RuntimeError("Pass one parser at least")
|
||||
|
||||
def extendedParser(input):
|
||||
snap = input.snapshot()
|
||||
self.parsers = parsers
|
||||
self.createNode = createNode
|
||||
self.exception = exception
|
||||
|
||||
results = []
|
||||
def _parse(self, input):
|
||||
snap = input.snapshot()
|
||||
parsedItems = []
|
||||
|
||||
for parser in parsers:
|
||||
result = parser(input)
|
||||
|
||||
if not result.result:
|
||||
if exception is not None:
|
||||
if callable(exception):
|
||||
raise exception(input)
|
||||
else:
|
||||
raise exception
|
||||
|
||||
input.reset(snap)
|
||||
return ParseResult.FAIL()
|
||||
|
||||
results.append(result.node)
|
||||
|
||||
node = createNode(*results)
|
||||
if not isinstance(node, Node):
|
||||
raise RuntimeError("Function 'createNode' haven't returned a Node object. Probably forget to pass 'return'")
|
||||
|
||||
return ParseResult.OK(node)
|
||||
|
||||
|
||||
return Parser(extendedParser, name=name, parsers=parsers)
|
||||
|
||||
|
||||
# leftAssociative -> left | left OP right
|
||||
@staticmethod
|
||||
def leftAssociativeOperatorParser(leftParser, operatorTokenTypes, rightParser, createNode, name="leftAssoc"):
|
||||
from smnp.ast.node.operator import Operator
|
||||
|
||||
def parse(input):
|
||||
operatorParser = Parser.oneOfTerminals(*operatorTokenTypes, createNode=lambda val, pos: Operator.withChildren([val], pos))
|
||||
left = leftParser(input)
|
||||
if left.result:
|
||||
operator = operatorParser(input)
|
||||
while operator.result:
|
||||
right = rightParser(input)
|
||||
left = ParseResult.OK(createNode(left.node, operator.node, right.node))
|
||||
operator = operatorParser(input)
|
||||
return left
|
||||
|
||||
return ParseResult.FAIL()
|
||||
|
||||
return Parser(parse, name=name, parsers=[leftParser, '|'.join([t.value for t in operatorTokenTypes]), rightParser])
|
||||
|
||||
@staticmethod
|
||||
def oneOfTerminals(*tokenTypes, createNode=None):
|
||||
return Parser.oneOf(*[Parser.terminal(expectedType, createNode=createNode) for expectedType in tokenTypes], name='|'.join([t.value for t in tokenTypes]))
|
||||
|
||||
# loop -> start item* end
|
||||
@staticmethod
|
||||
def loop(startParser, itemParser, endParser, createNode, name="loop"):
|
||||
def parse(input):
|
||||
items = []
|
||||
start = startParser(input)
|
||||
if start.result:
|
||||
while True:
|
||||
end = endParser(input)
|
||||
if end.result:
|
||||
return ParseResult.OK(createNode(start.node, items, end.node))
|
||||
item = itemParser(input)
|
||||
if not item.result:
|
||||
return ParseResult.FAIL()
|
||||
items.append(item.node)
|
||||
|
||||
return ParseResult.FAIL()
|
||||
|
||||
return Parser(parse, name, parsers=[startParser, itemParser, endParser])
|
||||
|
||||
@staticmethod
|
||||
def doAssert(parser, expected, name="!!"):
|
||||
def parse(input):
|
||||
result = parser(input)
|
||||
for parser in self.parsers:
|
||||
result = parser.parse(input)
|
||||
|
||||
if not result.result:
|
||||
found = f", found '{input.current().rawValue}'" if input.hasCurrent() else ''
|
||||
if self.exception is not None:
|
||||
if callable(self.exception):
|
||||
raise self.exception(input)
|
||||
else:
|
||||
raise self.exception
|
||||
|
||||
raise SyntaxException(f"Expected {expected}{found}", input.currentPos())
|
||||
input.reset(snap)
|
||||
return ParseResult.FAIL()
|
||||
|
||||
parsedItems.append(result.node)
|
||||
|
||||
node = self.createNode(*parsedItems)
|
||||
if not isinstance(node, Node):
|
||||
raise RuntimeError(f"Method 'createNode' of class '{self.__class__.__name__}' haven't returned a Node object. Probably forget to pass 'return'")
|
||||
|
||||
return ParseResult.OK(node)
|
||||
|
||||
def _grammarRules(self, output):
|
||||
output.append(self.name + ' -> ' + ' '.join([ parser.name for parser in self.parsers ]))
|
||||
[ parser._grammarRules(output) for parser in self.parsers ]
|
||||
|
||||
|
||||
class LeftAssociativeOperatorParser(Parser):
|
||||
def __init__(self, leftParser, operatorTokenTypes, rightParser, createNode, name):
|
||||
from smnp.ast.node.operator import Operator
|
||||
|
||||
super().__init__(name)
|
||||
self.leftParser = leftParser
|
||||
self.rightParser = rightParser
|
||||
self.createNode = createNode
|
||||
self.operators = operatorTokenTypes
|
||||
|
||||
operatorParsers = [ TerminalParser(expectedType, createNode=lambda val, pos: Operator.withValue(val, pos)) for expectedType in operatorTokenTypes ]
|
||||
self.operatorParser = OneOfParser(*operatorParsers, name="not important")
|
||||
|
||||
def _parse(self, input):
|
||||
snap = input.snapshot()
|
||||
left = self.leftParser.parse(input)
|
||||
if left.result:
|
||||
operator = self.operatorParser.parse(input)
|
||||
while operator.result:
|
||||
right = self.rightParser.parse(input)
|
||||
left = ParseResult.OK(self.createNode(left.node, operator.node, right.node))
|
||||
operator = self.operatorParser.parse(input)
|
||||
return left
|
||||
|
||||
return ParseResult.FAIL()
|
||||
|
||||
|
||||
def _grammarRules(self, output):
|
||||
output.append('\n'.join([f"{self.name} -> {self.leftParser.name} {operator.name.lower()} {self.rightParser.name} | {self.leftParser.name}" for operator in self.operators]))
|
||||
self.leftParser._grammarRules(output)
|
||||
self.rightParser._grammarRules(output)
|
||||
|
||||
|
||||
class ManyParser(Parser):
|
||||
def __init__(self, itemParser, createNode, name):
|
||||
super().__init__(name)
|
||||
self.itemParser = itemParser
|
||||
self.createNode = createNode
|
||||
|
||||
def _parse(self, input):
|
||||
snap = input.snapshot()
|
||||
|
||||
parsedItems = []
|
||||
pos = input.currentPos()
|
||||
while True:
|
||||
result = self.itemParser.parse(input)
|
||||
if result.result:
|
||||
parsedItems.append(result.node)
|
||||
snap = input.snapshot()
|
||||
else:
|
||||
input.reset(snap)
|
||||
return ParseResult.OK(self.createNode(parsedItems, pos) if len(parsedItems) > 0 else NoneNode())
|
||||
|
||||
def _grammarRules(self, output):
|
||||
output.append(f"{self.name} -> {self.itemParser.name}*")
|
||||
self.itemParser._grammarRules(output)
|
||||
|
||||
|
||||
class OptionalParser(Parser):
|
||||
def __init__(self, parser, name):
|
||||
super().__init__(name)
|
||||
self.parser = parser
|
||||
|
||||
def _parse(self, input):
|
||||
result = self.parser.parse(input)
|
||||
if result.result:
|
||||
return result
|
||||
|
||||
return Parser(parse, name, parsers=parser)
|
||||
return ParseResult.OK(NoneNode())
|
||||
|
||||
@staticmethod
|
||||
def optional(parser, name="??"):
|
||||
def parse(input):
|
||||
result = parser(input)
|
||||
if result.result:
|
||||
return result
|
||||
def _grammarRules(self, output):
|
||||
output.append(f"{self.name} -> {self.parser.name}?")
|
||||
|
||||
return ParseResult.OK(NoneNode())
|
||||
|
||||
return Parser(parse, name, parsers=[parser])
|
||||
class LoopParser(Parser):
|
||||
def __init__(self, startParser, itemParser, endParser, createNode, name):
|
||||
super().__init__(name)
|
||||
self.startParser = startParser
|
||||
self.itemParser = itemParser
|
||||
self.endParser = endParser
|
||||
self.createNode = createNode
|
||||
|
||||
@staticmethod
|
||||
def epsilon():
|
||||
return lambda *args: ParseResult.OK(NoneNode())
|
||||
|
||||
@staticmethod
|
||||
def many(parser, createNode, name="*"):
|
||||
def parse(input):
|
||||
results = []
|
||||
snap = input.snapshot()
|
||||
pos = input.currentPos()
|
||||
def _parse(self, input):
|
||||
items = []
|
||||
start = self.startParser.parse(input)
|
||||
if start.result:
|
||||
while True:
|
||||
result = parser(input)
|
||||
if result.result:
|
||||
results.append(result.node)
|
||||
snap = input.snapshot()
|
||||
else:
|
||||
input.reset(snap)
|
||||
return ParseResult.OK(createNode(results, pos) if len(results) > 0 else NoneNode())
|
||||
end = self.endParser.parse(input)
|
||||
if end.result:
|
||||
return ParseResult.OK(self.createNode(start.node, items, end.node))
|
||||
item = self.itemParser.parse(input)
|
||||
if not item.result:
|
||||
return ParseResult.FAIL()
|
||||
items.append(item.node)
|
||||
|
||||
return Parser(parse, name, parsers=[parser])
|
||||
return ParseResult.FAIL()
|
||||
|
||||
@staticmethod
|
||||
def wrap(parser, createNode):
|
||||
def parse(input):
|
||||
result = parser(input)
|
||||
if result.result:
|
||||
return ParseResult.OK(createNode(result.node))
|
||||
def _grammarRules(self, output):
|
||||
output.append(f"{self.name} -> {self.startParser.name} {self.itemParser.name}* {self.endParser.name}")
|
||||
self.startParser._grammarRules(output)
|
||||
self.itemParser._grammarRules(output)
|
||||
self.endParser._grammarRules(output)
|
||||
|
||||
return result
|
||||
|
||||
return parse
|
||||
@@ -10,9 +10,6 @@ class Sound:
|
||||
def play(self):
|
||||
sd.play(self.data, self.fs, blocking=True)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.file == other.file and self.data == other.data
|
||||
|
||||
def __str__(self):
|
||||
return f"sound[{self.file}]"
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import argparse
|
||||
|
||||
VERSION = "0.1"
|
||||
DESCRIPTION = """
|
||||
Simple Music Notation Processor is a command line tool enabling you to do some music stuff using custom domain-specific language.
|
||||
"""
|
||||
|
||||
class CliParser(object):
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser(description=DESCRIPTION)
|
||||
self.parser.add_argument('file', nargs='*', help='a file containing SMNP code')
|
||||
self.parser.add_argument('-c', '--code', action='append', default=[], type=str, help='a string with SMNP code')
|
||||
self.parser.add_argument('-m', '--mic', action='store_true', help='test microphone level')
|
||||
self.parser.add_argument('-C', '--config', type=argparse.FileType('-r'), help='a file containing settings (not implemented yet)')
|
||||
self.parser.add_argument('-p', '--params', action='append', help='pass arguments to program (not implemented yet)')
|
||||
self.parser.add_argument('-v', '--version', action='version')
|
||||
self.parser.add_argument('--tokens', action='store_true', help='print tokens of parsed code')
|
||||
self.parser.add_argument('--ast', action='store_true', help='print abstract syntax tree of parsed code')
|
||||
self.parser.add_argument('--dry-run', action='store_true', help='don\'t execute passed code')
|
||||
self.parser.version = VERSION
|
||||
|
||||
def parse(self):
|
||||
return self.parser.parse_args()
|
||||
@@ -1,19 +1,17 @@
|
||||
from smnp.error.function import FunctionNotFoundException, MethodNotFoundException, IllegalFunctionInvocationException
|
||||
from smnp.error.runtime import RuntimeException
|
||||
from smnp.function.tools import argsTypesToString
|
||||
from smnp.runtime.evaluators.function import BodyEvaluator, Return
|
||||
from smnp.type.model import Type
|
||||
from smnp.runtime.evaluators.function import BodyEvaluator
|
||||
|
||||
|
||||
class Environment():
|
||||
def __init__(self, scopes, functions, methods, source):
|
||||
def __init__(self, scopes, functions, methods):
|
||||
self.scopes = scopes
|
||||
self.functions = functions
|
||||
self.methods = methods
|
||||
self.customFunctions = []
|
||||
self.customMethods = []
|
||||
self.callStack = []
|
||||
self.source = source
|
||||
|
||||
def invokeMethod(self, object, name, args):
|
||||
builtinMethodResult = self._invokeBuiltinMethod(object, name, args)
|
||||
@@ -40,15 +38,10 @@ class Environment():
|
||||
if method.typeSignature.check([object])[0] and method.name == name: #Todo sprawdzic sygnature typu
|
||||
signatureCheckresult = method.signature.check(args)
|
||||
if signatureCheckresult[0]:
|
||||
self.scopes.append(method.defaultArgs)
|
||||
self.scopes[-1].update({argName: argValue for argName, argValue in zip(method.arguments, list(signatureCheckresult[1:]))})
|
||||
self.scopes.append({argName: argValue for argName, argValue in zip(method.arguments, list(signatureCheckresult[1:]))})
|
||||
self.scopes[-1][method.alias] = object
|
||||
self.callStack.append(CallStackItem(name))
|
||||
result = Type.void()
|
||||
try:
|
||||
BodyEvaluator.evaluate(method.body, self).value # TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
|
||||
except Return as r:
|
||||
result = r.value
|
||||
result = BodyEvaluator.evaluate(method.body, self).value # TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
|
||||
self.callStack.pop(-1)
|
||||
self.scopes.pop(-1)
|
||||
return (True, result)
|
||||
@@ -81,27 +74,20 @@ class Environment():
|
||||
if function.name == name:
|
||||
signatureCheckresult = function.signature.check(args)
|
||||
if signatureCheckresult[0]:
|
||||
self.appendScope(function.defaultArgs)
|
||||
appendedScopeIndex = len(self.scopes)-1
|
||||
self.scopes[-1].update({ argName: argValue for argName, argValue in zip(function.arguments, list(signatureCheckresult[1:])) })
|
||||
self.scopes.append({ argName: argValue for argName, argValue in zip(function.arguments, list(signatureCheckresult[1:])) })
|
||||
self.callStack.append(CallStackItem(name))
|
||||
result = Type.void()
|
||||
try:
|
||||
BodyEvaluator.evaluate(function.body, self).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
|
||||
except Return as r:
|
||||
result = r.value
|
||||
result = BodyEvaluator.evaluate(function.body, self).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
|
||||
self.callStack.pop(-1)
|
||||
self.popScope(mergeVariables=False)
|
||||
self.removeScopesAfter(appendedScopeIndex)
|
||||
self.scopes.pop(-1)
|
||||
return (True, result)
|
||||
raise IllegalFunctionInvocationException(f"{function.name}{function.signature.string}", f"{name}{argsTypesToString(args)}")
|
||||
return (False, None)
|
||||
|
||||
def addCustomFunction(self, name, signature, arguments, body, defaultArguments):
|
||||
def addCustomFunction(self, name, signature, arguments, body):
|
||||
if len([fun for fun in self.functions + self.customFunctions if fun.name == name]) > 0:
|
||||
raise RuntimeException(f"Cannot redeclare function '{name}'", None)
|
||||
|
||||
self.customFunctions.append(CustomFunction(name, signature, arguments, body, defaultArguments))
|
||||
self.customFunctions.append(CustomFunction(name, signature, arguments, body))
|
||||
|
||||
# TODO:
|
||||
# There is still problem with checking existing of generic types, like lists:
|
||||
@@ -112,14 +98,14 @@ class Environment():
|
||||
# function foo() { return 2 }
|
||||
# }
|
||||
# Then calling [1, 2, 3, 4].foo() will produce 1, when the second method is more suitable
|
||||
def addCustomMethod(self, typeSignature, alias, name, signature, arguments, body, defaultArguments):
|
||||
def addCustomMethod(self, typeSignature, alias, name, signature, arguments, body):
|
||||
if len([m for m in self.methods if m.name == name and m.signature.matchers[0] == typeSignature.matchers[0]]) > 0:
|
||||
raise RuntimeException(f"Cannot redeclare method '{name}' for type '{typeSignature.matchers[0]}'", None)
|
||||
|
||||
if len([m for m in self.customMethods if m.name == name and m.typeSignature.matchers[0] == typeSignature.matchers[0]]) > 0:
|
||||
raise RuntimeException(f"Cannot redeclare method '{name}' for type '{typeSignature.matchers[0]}'", None)
|
||||
|
||||
self.customMethods.append(CustomMethod(typeSignature, alias, name, signature, arguments, body, defaultArguments))
|
||||
self.customMethods.append(CustomMethod(typeSignature, alias, name, signature, arguments, body))
|
||||
|
||||
def findVariable(self, name, type=None, pos=None):
|
||||
for scope in reversed(self.scopes):
|
||||
@@ -142,20 +128,6 @@ class Environment():
|
||||
else:
|
||||
return scope
|
||||
|
||||
def appendScope(self, variables=None):
|
||||
if variables is None:
|
||||
variables = {}
|
||||
|
||||
self.scopes.append(variables)
|
||||
|
||||
def popScope(self, mergeVariables=True):
|
||||
lastScope = self.scopes.pop(-1)
|
||||
if mergeVariables:
|
||||
self.scopes[-1].update(lastScope)
|
||||
|
||||
def removeScopesAfter(self, index):
|
||||
del self.scopes[index:]
|
||||
|
||||
def scopesToString(self):
|
||||
return "Scopes:\n" + ("\n".join([ f" [{i}]: {scope}" for i, scope in enumerate(self.scopes) ]))
|
||||
|
||||
@@ -190,23 +162,22 @@ class Environment():
|
||||
class CallStackItem:
|
||||
def __init__(self, function):
|
||||
self.function = function
|
||||
self.value = None
|
||||
|
||||
|
||||
class CustomFunction:
|
||||
def __init__(self, name, signature, arguments, body, defaultArgs):
|
||||
def __init__(self, name, signature, arguments, body):
|
||||
self.name = name
|
||||
self.signature = signature
|
||||
self.arguments = arguments
|
||||
self.body = body
|
||||
self.defaultArgs = defaultArgs
|
||||
|
||||
|
||||
class CustomMethod:
|
||||
def __init__(self, typeSignature, alias, name, signature, arguments, body, defaultArgs):
|
||||
def __init__(self, typeSignature, alias, name, signature, arguments, body):
|
||||
self.typeSignature = typeSignature
|
||||
self.alias = alias
|
||||
self.name = name
|
||||
self.signature = signature
|
||||
self.arguments = arguments
|
||||
self.body = body
|
||||
self.defaultArgs = defaultArgs
|
||||
self.body = body
|
||||
@@ -1,3 +1,7 @@
|
||||
from smnp.environment.environment import Environment
|
||||
from smnp.module import functions, methods
|
||||
|
||||
|
||||
def createEnvironment():
|
||||
return
|
||||
return Environment([{}], functions, methods)
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ class SmnpException(Exception):
|
||||
def __init__(self, msg, pos):
|
||||
self.msg = msg
|
||||
self.pos = pos
|
||||
self.file = None
|
||||
|
||||
def _title(self):
|
||||
pass
|
||||
@@ -11,10 +10,7 @@ class SmnpException(Exception):
|
||||
return ""
|
||||
|
||||
def _position(self):
|
||||
return "" if self.pos is None else f"[line {self.pos[0]+1}, col {self.pos[1]+1}]"
|
||||
|
||||
def _file(self):
|
||||
return "" if self.file is None else f"File: {self.file}"
|
||||
return "" if self.pos is None else f" [line {self.pos[0]+1}, col {self.pos[1]+1}]"
|
||||
|
||||
def message(self):
|
||||
return f"{self._title()}\n{self._file()} {self._position()}\n\n{self.msg}\n{self._postMessage()}"
|
||||
return f"{self._title()}{self._position()}:\n{self.msg}\n{self._postMessage()}"
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
from smnp.error.runtime import RuntimeException
|
||||
|
||||
|
||||
class CustomException(RuntimeException):
|
||||
def __init__(self, message, pos):
|
||||
super().__init__(message, pos)
|
||||
|
||||
def _title(self):
|
||||
return "Execution Error"
|
||||
|
||||
def _postMessage(self):
|
||||
return "\n" + self.environment.callStackToString() if len(self.environment.callStack) > 0 else ""
|
||||
@@ -12,9 +12,6 @@ class Signature:
|
||||
|
||||
def varargSignature(varargMatcher, *basicSignature, wrapVarargInValue=False):
|
||||
def check(args):
|
||||
if any([ matcher.optional for matcher in [ varargMatcher, *basicSignature ]]):
|
||||
raise RuntimeError("Vararg signature can't have optional arguments")
|
||||
|
||||
if len(basicSignature) > len(args):
|
||||
return doesNotMatchVararg(basicSignature)
|
||||
|
||||
@@ -41,7 +38,7 @@ def doesNotMatchVararg(basicSignature):
|
||||
|
||||
def signature(*signature):
|
||||
def check(args):
|
||||
if len(args) > len(signature) or len(args) < len([ matcher for matcher in signature if not matcher.optional ]):
|
||||
if len(signature) != len(args):
|
||||
return doesNotMatch(signature)
|
||||
|
||||
for s, a in zip(signature, args):
|
||||
@@ -55,12 +52,6 @@ def signature(*signature):
|
||||
return Signature(check, string, signature)
|
||||
|
||||
|
||||
def optional(matcher):
|
||||
matcher.optional = True
|
||||
matcher.string += "?"
|
||||
return matcher
|
||||
|
||||
|
||||
def doesNotMatch(sign):
|
||||
return (False, *[None for n in sign])
|
||||
|
||||
|
||||
@@ -1,492 +0,0 @@
|
||||
function flat(list lists...) {
|
||||
return _flat(lists as l ^ _flat(l, []), []);
|
||||
}
|
||||
|
||||
function _flat(list l, list output) {
|
||||
l as elem ^ {
|
||||
if (typeOf(elem) == list) {
|
||||
output = _flat(elem, output);
|
||||
} else {
|
||||
output = output + [elem];
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
extend note as n {
|
||||
function withOctave(integer octave) {
|
||||
return Note(n.pitch, octave, n.duration, n.dot);
|
||||
}
|
||||
|
||||
function withDuration(integer duration) {
|
||||
return Note(n.pitch, n.octave, duration, n.dot);
|
||||
}
|
||||
|
||||
function withDot(bool dot) {
|
||||
return Note(n.pitch, n.octave, n.duration, dot);
|
||||
}
|
||||
|
||||
function toIntRepr() {
|
||||
return n.octave * 12 + _pitchToNumber(n.pitch);
|
||||
}
|
||||
|
||||
function transpose(integer value) {
|
||||
return noteFromIntRepr(n.toIntRepr() + value, n.duration, n.dot);
|
||||
}
|
||||
}
|
||||
|
||||
function noteFromIntRepr(integer intRepr, integer duration, bool dot) {
|
||||
pitch = _numberToPitch(mod(intRepr, 12));
|
||||
octave = Integer(intRepr / 12);
|
||||
return Note(pitch, octave, duration, dot);
|
||||
}
|
||||
|
||||
function mod(integer a, integer b) {
|
||||
return a - b * Integer(a/b);
|
||||
}
|
||||
|
||||
function _pitchToNumber(string pitch) {
|
||||
return _keysToIntMapper(
|
||||
"C",
|
||||
"CIS",
|
||||
"D",
|
||||
"DIS",
|
||||
"E",
|
||||
"F",
|
||||
"FIS",
|
||||
"G",
|
||||
"GIS",
|
||||
"A",
|
||||
"AIS",
|
||||
"H"
|
||||
).get(pitch);
|
||||
}
|
||||
|
||||
function _keysToIntMapper(keys...) {
|
||||
return Map(keys as (i, key) ^ [key, i]);
|
||||
}
|
||||
|
||||
function _numberToPitch(integer number) {
|
||||
return ["C", "CIS", "D", "DIS", "E", "F", "FIS", "G", "GIS", "A", "AIS", "H"].get(number);
|
||||
}
|
||||
|
||||
function transpose(integer value, <note, integer, list<note, integer>> notes...) {
|
||||
if (notes.size == 1) {
|
||||
first = notes.get(0);
|
||||
if (typeOf(first) == integer) {
|
||||
return first;
|
||||
} else if (typeOf(first) == note) {
|
||||
return first.transpose(value);
|
||||
} else if (typeOf(first) == list) {
|
||||
return _transpose(value, first);
|
||||
}
|
||||
}
|
||||
|
||||
noteOrInteger = false;
|
||||
lists = false;
|
||||
|
||||
notes as n ^ {
|
||||
if (typeOf(n) == note or typeOf(n) == integer) {
|
||||
noteOrInteger = true;
|
||||
if (lists) {
|
||||
throw "Mixing notes and integers with lists of them is not supported";
|
||||
}
|
||||
} else if (typeOf(n) == list) {
|
||||
lists = true;
|
||||
if (noteOrInteger) {
|
||||
throw "Mixing notes and integers with lists of them is not supported";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output = [];
|
||||
notes as n ^ {
|
||||
if (typeOf(n) == integer) {
|
||||
output = output + [n];
|
||||
} else if (typeOf(n) == note) {
|
||||
output = output + [n.transpose(value)];
|
||||
} else if (typeOf(n) == list) {
|
||||
output = output + [_transpose(value, n)];
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function _transpose(integer value, list<note, integer> notes) {
|
||||
output = [];
|
||||
notes as n ^ {
|
||||
if (typeOf(n) == integer) {
|
||||
output = output + [n];
|
||||
} else if (typeOf(n) == note) {
|
||||
output = output + [n.transpose(value)];
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
function transposeTo(note target, <note, integer, list<note, integer>> notes...) {
|
||||
if (notes.size == 1) {
|
||||
first = notes.get(0);
|
||||
if (typeOf(first) == integer) {
|
||||
return first;
|
||||
} else if (typeOf(first) == note) {
|
||||
return _transposeTo(target, notes).get(0);
|
||||
} else if (typeOf(first) == list) {
|
||||
return _transposeTo(target, first);
|
||||
}
|
||||
}
|
||||
|
||||
noteOrInteger = false;
|
||||
lists = false;
|
||||
|
||||
notes as n ^ {
|
||||
if (typeOf(n) == note or typeOf(n) == integer) {
|
||||
noteOrInteger = true;
|
||||
if (lists) {
|
||||
throw "Mixing notes and integers with lists of them is not supported";
|
||||
}
|
||||
} else if (typeOf(n) == list) {
|
||||
lists = true;
|
||||
if (noteOrInteger) {
|
||||
throw "Mixing notes and integers with lists of them is not supported";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (noteOrInteger) {
|
||||
return _transposeTo(target, notes);
|
||||
}
|
||||
|
||||
if (lists) {
|
||||
return notes as n ^ _transposeTo(target, n);
|
||||
}
|
||||
}
|
||||
|
||||
function _transposeTo(note target, list<note, integer> notes) {
|
||||
if (notes.size == 0) {
|
||||
throw "Provide list with one note at least";
|
||||
}
|
||||
|
||||
firstNote = notes.get(0);
|
||||
semitones = semitones(firstNote, target);
|
||||
return transpose(semitones, notes);
|
||||
}
|
||||
|
||||
function tuplet(integer n, integer m, note notes...) {
|
||||
if (n != notes.size) {
|
||||
throw "Expected " + n.toString() + " notes exactly, whereas " + notes.size.toString() + " was passed";
|
||||
}
|
||||
|
||||
return notes as x ^ x.withDuration(x.duration * n / m);
|
||||
}
|
||||
|
||||
extend list as l with function contains(expectedValue) {
|
||||
return (l as value ^ value % value == expectedValue).size > 0;
|
||||
}
|
||||
|
||||
extend map as m {
|
||||
function containsKey(expectedKey) {
|
||||
return m.keys.contains(expectedKey);
|
||||
}
|
||||
|
||||
function containsValue(expectedValue) {
|
||||
return m.values.contains(expectedValue);
|
||||
}
|
||||
|
||||
function contains(key, value) {
|
||||
if (m.keys.contains(key)) {
|
||||
return m.get(key) == value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function sample(items...) {
|
||||
if (items.size == 0) {
|
||||
throw "Provide one item at least";
|
||||
}
|
||||
|
||||
if (items.size == 1 and typeOf(items) == list) {
|
||||
return items.get(0).get(rand(0, items.get(0).size-1));
|
||||
}
|
||||
|
||||
return items.get(rand(0, items.size-1));
|
||||
}
|
||||
|
||||
extend string as s with function join(list<string> l) {
|
||||
output = "";
|
||||
l as (index, item) ^ {
|
||||
output = output + item;
|
||||
if (index < l.size - 1) {
|
||||
output = output + s;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function random(map<string><> items...) {
|
||||
accumulator = 0;
|
||||
items as (index, item) ^ {
|
||||
if (item.size != 2) {
|
||||
throw "Expected lists with two items: percent and value";
|
||||
}
|
||||
|
||||
if (not item.containsKey("percent")) {
|
||||
throw "Item " + (index+1).toString() + " does not have 'percent' key";
|
||||
}
|
||||
|
||||
if (not item.containsKey("value")) {
|
||||
throw "Item " + (index+1).toString() + " does not have 'value' key";
|
||||
}
|
||||
|
||||
accumulator = accumulator + item.get("percent");
|
||||
}
|
||||
|
||||
if (accumulator != 100) {
|
||||
throw "Sum of first element of each item must be equal to 100";
|
||||
}
|
||||
|
||||
accumulator = 0;
|
||||
random = rand(0, 99);
|
||||
items as item ^ {
|
||||
accumulator = accumulator + item.get("percent");
|
||||
if (random < accumulator) {
|
||||
return item.get("value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function semitones(<note, integer, list<note, integer>> notes...) {
|
||||
noteOrInteger = false;
|
||||
lists = false;
|
||||
|
||||
notes as n ^ {
|
||||
if (typeOf(n) == note or typeOf(n) == integer) {
|
||||
noteOrInteger = true;
|
||||
if (lists) {
|
||||
throw "Mixing notes and integers with lists of them is not supported";
|
||||
}
|
||||
} else if (typeOf(n) == list) {
|
||||
lists = true;
|
||||
if (noteOrInteger) {
|
||||
throw "Mixing notes and integers with lists of them is not supported";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (noteOrInteger) {
|
||||
return _semitones(notes);
|
||||
}
|
||||
|
||||
if (lists) {
|
||||
output = [];
|
||||
notes as n ^ {
|
||||
output = output + [_semitones(n)];
|
||||
}
|
||||
|
||||
#if (output.size == 1) {
|
||||
# return output.get(0)
|
||||
#}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function _semitones(list<note, integer> notes) {
|
||||
onlyNotes = notes as n ^ n % typeOf(n) == note;
|
||||
|
||||
if (onlyNotes.size == 2 and typeOf(onlyNotes.get(0)) == note and typeOf(onlyNotes.get(1)) == note) {
|
||||
first = onlyNotes.get(0);
|
||||
second = onlyNotes.get(1);
|
||||
return second.toIntRepr() - first.toIntRepr();
|
||||
}
|
||||
|
||||
if (onlyNotes.size < 2) {
|
||||
throw "Provide 2 notes at least to evaluate semitones between them";
|
||||
}
|
||||
|
||||
output = [];
|
||||
range(1, onlyNotes.size-1) as i ^ {
|
||||
output = output + [onlyNotes.get(i).toIntRepr() - onlyNotes.get(i-1).toIntRepr()];
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function stringInterval(integer semitones) {
|
||||
return [
|
||||
"1",
|
||||
"2m",
|
||||
"2M",
|
||||
"3m",
|
||||
"3M",
|
||||
"4",
|
||||
"5d/4A",
|
||||
"5",
|
||||
"6m",
|
||||
"6M",
|
||||
"7m",
|
||||
"7M"
|
||||
].get(semitones);
|
||||
}
|
||||
|
||||
function interval(<note, integer, list<note, integer>> notes...) {
|
||||
noteOrInteger = false;
|
||||
lists = false;
|
||||
|
||||
notes as n ^ {
|
||||
if (typeOf(n) == note or typeOf(n) == integer) {
|
||||
noteOrInteger = true;
|
||||
if (lists) {
|
||||
throw "Mixing notes and integers with lists of them is not supported";
|
||||
}
|
||||
} else if (typeOf(n) == list) {
|
||||
lists = true;
|
||||
if (noteOrInteger) {
|
||||
throw "Mixing notes and integers with lists of them is not supported";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (noteOrInteger) {
|
||||
semitones = _semitones(notes);
|
||||
if (typeOf(semitones) == list) {
|
||||
return semitones as n ^ stringInterval(n);
|
||||
} else {
|
||||
return stringInterval(semitones);
|
||||
}
|
||||
}
|
||||
|
||||
if (lists) {
|
||||
output = [];
|
||||
notes as n ^ {
|
||||
semitones = _semitones(n);
|
||||
if (typeOf(semitones) == list) {
|
||||
output = output + [_semitones(n) as semitone ^ stringInterval(semitone)];
|
||||
} else {
|
||||
output = output + [stringInterval(semitones)];
|
||||
}
|
||||
}
|
||||
|
||||
#if (output.size == 1) {
|
||||
# return output.get(0);
|
||||
#}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function noteRange(note a, note b, string filter = "all") {
|
||||
filters = {
|
||||
"all" -> [ "C", "CIS", "D", "DIS", "E", "F", "FIS", "G", "GIS", "A", "AIS", "H" ],
|
||||
"diatonic" -> [ "C", "D", "E", "F", "G", "A", "H" ],
|
||||
"chromatic" -> [ "CIS", "DIS", "FIS", "GIS", "AIS" ]
|
||||
};
|
||||
|
||||
if (not filters.containsKey(filter)) {
|
||||
throw "Unknown filter: '" + filter + "'";
|
||||
}
|
||||
|
||||
notes = range(a.toIntRepr(), b.toIntRepr()) as intRepr ^ noteFromIntRepr(intRepr, a.duration, a.dot);
|
||||
return notes as n ^ n % filters.get(filter).contains(n.pitch);
|
||||
|
||||
}
|
||||
|
||||
function range(<integer, float> a, <integer, float> b, <integer, float> step = 1) {
|
||||
if (not (step > 0)) {
|
||||
throw "Step should be greater than 0";
|
||||
}
|
||||
|
||||
if (a > b) {
|
||||
throw "Upper range value should be greater than lower or equal to";
|
||||
}
|
||||
|
||||
output = [];
|
||||
|
||||
i = a;
|
||||
i <= b ^ {
|
||||
output = output + [i];
|
||||
i = i + step;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function alert(<integer, bool> cycles = true, string melody = "beep", list<float, integer> overtones = [0.5, 0.0, 0.0, 0.5]) {
|
||||
if (not [integer, bool].contains(typeOf(cycles))) {
|
||||
throw "Provide 'true' or number of cycles as first argument";
|
||||
}
|
||||
|
||||
if (typeOf(cycles) == integer) {
|
||||
if (cycles < 1) {
|
||||
throw "Number of cycles cannot be less than 1";
|
||||
}
|
||||
}
|
||||
|
||||
if (typeOf(cycles) == bool) {
|
||||
if (not cycles) {
|
||||
throw "Provide 'true' or number of cycles as first argument";
|
||||
}
|
||||
}
|
||||
|
||||
notes = {
|
||||
"beep" -> [@c5:16, 32, @c5:16, 3],
|
||||
"s1" -> noteRange(@c5:32, @g5:32),
|
||||
"s2" -> _upDown(noteRange(@c5:32, @g5:32)),
|
||||
"s3" -> [@a5:16, @d5:16],
|
||||
"semitone" -> [@c5:16, @db5:16]
|
||||
};
|
||||
|
||||
if (not notes.containsKey(melody)) {
|
||||
throw "Unknown melody '" + melody + "'. Available: 'beep', 's1', 's2', 's3' and 'semitone'";
|
||||
}
|
||||
|
||||
config = {
|
||||
bpm -> 120,
|
||||
decay -> 0.5,
|
||||
attack -> 200,
|
||||
overtones -> overtones
|
||||
};
|
||||
|
||||
wave = wave(config, notes.get(melody));
|
||||
|
||||
cycles ^ synth(wave);
|
||||
}
|
||||
|
||||
function _upDown(list l) {
|
||||
return l + -l;
|
||||
}
|
||||
|
||||
function metronome(integer bpm = 120, integer beats = 4, countMeasures = false) {
|
||||
accent = wave({
|
||||
overtones -> flat([0.5, 0.1, 10^0, 0.1, 10^0, 0.1, 20^0, 0.1, 25^0, 0.05, 25^0, 0.05]),
|
||||
attack -> 0,
|
||||
decay -> 5,
|
||||
bpm -> bpm
|
||||
}, @c);
|
||||
|
||||
beat = wave({
|
||||
overtones -> flat([0.5, 10^0, 0.3, 10^0, 0.2]),
|
||||
attack -> 0,
|
||||
decay -> 100,
|
||||
bpm -> bpm
|
||||
}, @c);
|
||||
|
||||
measure = 1;
|
||||
true ^ {
|
||||
if (countMeasures) {
|
||||
println(measure);
|
||||
measure = measure + 1;
|
||||
}
|
||||
synth(accent);
|
||||
beats - 1 ^ synth(beat);
|
||||
}
|
||||
}
|
||||
@@ -5,5 +5,7 @@ from smnp.program.interpreter import Interpreter
|
||||
|
||||
def loadStandardLibrary():
|
||||
mainSource = resource_string('smnp.library.code', 'main.mus').decode("utf-8")
|
||||
env = Interpreter.interpretString(mainSource, "<stdlib>")
|
||||
return env
|
||||
boolSource = resource_string('smnp.library.code', 'bool.mus').decode("utf-8")
|
||||
env = Interpreter.interpretString(mainSource)
|
||||
return Interpreter.interpretString(boolSource, baseEnvironment=env)
|
||||
|
||||
|
||||
45
smnp/main.py
@@ -1,38 +1,35 @@
|
||||
from smnp.cli.parser import CliParser
|
||||
from smnp.ast.node.atom import AtomParser
|
||||
from smnp.ast.node.chain import ChainParser
|
||||
from smnp.ast.node.list import ListParser
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.error.base import SmnpException
|
||||
from smnp.library.loader import loadStandardLibrary
|
||||
from smnp.module.mic.lib.detector.noise import NoiseDetector
|
||||
from smnp.program.interpreter import Interpreter
|
||||
|
||||
|
||||
def interpretFile(args, file):
|
||||
stdLibraryEnv = loadStandardLibrary() if not args.dry_run else None
|
||||
Interpreter.interpretFile(file, printTokens=args.tokens, printAst=args.ast, execute=not args.dry_run, baseEnvironment=stdLibraryEnv)
|
||||
|
||||
|
||||
def interpretString(args, string):
|
||||
stdLibraryEnv = loadStandardLibrary() if not args.dry_run else None
|
||||
Interpreter.interpretString(string, printTokens=args.tokens, printAst=args.ast, execute=not args.dry_run, baseEnvironment=stdLibraryEnv, source='<cli>')
|
||||
from smnp.token.tokenizer import tokenize
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
parser = CliParser()
|
||||
args = parser.parse()
|
||||
# stdLibraryEnv = loadStandardLibrary()
|
||||
# Interpreter.interpretFile(sys.argv[1], printTokens=True, printAst=True, execute=False, baseEnvironment=None)
|
||||
# draft()
|
||||
|
||||
if args.mic:
|
||||
nd = NoiseDetector()
|
||||
nd.test()
|
||||
class TestNode(Node):
|
||||
def __init__(self, children):
|
||||
super().__init__((-1, -1))
|
||||
self.children = children
|
||||
|
||||
for code in args.code:
|
||||
interpretString(args, code)
|
||||
tokens = tokenize(['[1, 2]'])
|
||||
parser = ListParser()
|
||||
#print(parser.grammar())
|
||||
res = parser.parse(tokens)
|
||||
|
||||
for file in args.file:
|
||||
interpretFile(args, file)
|
||||
print()
|
||||
if res.result:
|
||||
res.node.print()
|
||||
else:
|
||||
print("nie sparsowano")
|
||||
|
||||
except SmnpException as e:
|
||||
print(e.message())
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("Program interrupted")
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from smnp.module import system, mic, note, iterable, sound, synth, string, util, integer, float
|
||||
from smnp.module import system, mic, note, iterable, sound, synth, string, util
|
||||
|
||||
functions = [ *system.functions, *mic.functions, *note.functions, *iterable.functions, *sound.functions, *synth.functions, *string.functions, *util.functions, *integer.functions, *float.functions ]
|
||||
methods = [ *system.methods, *mic.methods, *note.methods, *iterable.methods, *sound.methods, *synth.methods, *string.methods, *util.methods, *integer.methods, *float.methods ]
|
||||
functions = [ *system.functions, *mic.functions, *note.functions, *iterable.functions, *sound.functions, *synth.functions, *string.functions, *util.functions ]
|
||||
methods = [ *system.methods, *mic.methods, *note.methods, *iterable.methods, *sound.methods, *synth.methods, *string.functions, *util.methods ]
|
||||
@@ -1,4 +0,0 @@
|
||||
from smnp.module.float.function import float
|
||||
|
||||
functions = [ float.function ]
|
||||
methods = []
|
||||
@@ -1,26 +0,0 @@
|
||||
from smnp.function.model import CombinedFunction, Function
|
||||
from smnp.function.signature import signature
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.type import ofType
|
||||
|
||||
_signature1 = signature(ofType(Type.INTEGER))
|
||||
def _function1(env, value):
|
||||
return Type.float(float(value.value))
|
||||
|
||||
|
||||
_signature2 = signature(ofType(Type.STRING))
|
||||
def _function2(env, value):
|
||||
return Type.float(float(value.value))
|
||||
|
||||
|
||||
_signature3 = signature(ofType(Type.FLOAT))
|
||||
def _function3(env, value):
|
||||
return value
|
||||
|
||||
|
||||
function = CombinedFunction(
|
||||
'Float',
|
||||
Function(_signature1, _function1),
|
||||
Function(_signature2, _function2),
|
||||
Function(_signature3, _function3),
|
||||
)
|
||||
@@ -1,4 +0,0 @@
|
||||
from smnp.module.integer.function import integer
|
||||
|
||||
functions = [ integer.function ]
|
||||
methods = []
|
||||
@@ -1,25 +0,0 @@
|
||||
from smnp.function.model import CombinedFunction, Function
|
||||
from smnp.function.signature import signature
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.type import ofType
|
||||
|
||||
_signature1 = signature(ofType(Type.FLOAT))
|
||||
def _function1(env, value):
|
||||
return Type.integer(int(value.value))
|
||||
|
||||
|
||||
_signature2 = signature(ofType(Type.STRING))
|
||||
def _function2(env, value):
|
||||
return Type.integer(int(value.value))
|
||||
|
||||
|
||||
_signature3 = signature(ofType(Type.INTEGER))
|
||||
def _function3(env, value):
|
||||
return value
|
||||
|
||||
function = CombinedFunction(
|
||||
'Integer',
|
||||
Function(_signature1, _function1),
|
||||
Function(_signature2, _function2),
|
||||
Function(_signature3, _function3),
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
from smnp.module.iterable.function import map, get
|
||||
from smnp.module.iterable.function import combine, flat, map, range, get
|
||||
|
||||
functions = [ map.function ]
|
||||
functions = [ combine.function, flat.function, map.function, range.function ]
|
||||
methods = [ get.function ]
|
||||
18
smnp/module/iterable/function/combine.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from functools import reduce
|
||||
|
||||
from smnp.function.model import Function
|
||||
from smnp.function.signature import varargSignature
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.type import ofTypes
|
||||
|
||||
_signature = varargSignature(ofTypes(Type.LIST))
|
||||
def _function(env, vararg):
|
||||
if len(vararg) == 1:
|
||||
return vararg[0]
|
||||
|
||||
combined = reduce(lambda x, y: x.value + y.value, vararg)
|
||||
return Type.list(combined)
|
||||
|
||||
|
||||
function = Function(_signature, _function, 'combine')
|
||||
|
||||
23
smnp/module/iterable/function/flat.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from smnp.function.model import Function
|
||||
from smnp.function.signature import varargSignature
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.type import allTypes
|
||||
|
||||
_signature = varargSignature(allTypes())
|
||||
def _function(env, vararg):
|
||||
return Type.list(doFlat(vararg, [])).decompose()
|
||||
|
||||
|
||||
def doFlat(input, output=None):
|
||||
if output is None:
|
||||
output = []
|
||||
|
||||
for item in input:
|
||||
if item.type == Type.LIST:
|
||||
doFlat(item.value, output)
|
||||
else:
|
||||
output.append(item)
|
||||
return output
|
||||
|
||||
|
||||
function = Function(_signature, _function, 'flat')
|
||||
36
smnp/module/iterable/function/range.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from smnp.function.model import CombinedFunction, Function
|
||||
from smnp.function.signature import signature
|
||||
from smnp.note.model import Note
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.type import ofType
|
||||
|
||||
_signature1 = signature(ofType(Type.INTEGER))
|
||||
def _function1(env, upper):
|
||||
return Type.list(list(range(upper.value + 1)))
|
||||
|
||||
|
||||
_signature2 = signature(ofType(Type.INTEGER), ofType(Type.INTEGER))
|
||||
def _function2(env, lower, upper):
|
||||
return Type.list(list(range(lower.value, upper.value + 1)))
|
||||
|
||||
|
||||
_signature3 = signature(ofType(Type.INTEGER), ofType(Type.INTEGER), ofType(Type.INTEGER))
|
||||
def _function3(env, lower, upper, step):
|
||||
return Type.list(list(range(lower.value, upper.value + 1, step.value)))
|
||||
|
||||
|
||||
_signature4 = signature(ofType(Type.NOTE), ofType(Type.NOTE))
|
||||
def _function4(env, lower, upper):
|
||||
return Type.list([Type.note(n) for n in Note.range(lower.value, upper.value)])
|
||||
|
||||
|
||||
# TODO
|
||||
# signature5 = range(note lower, note upper, integer step) OR step = "diatonic" | "chromatic" | "augmented" | "diminish"
|
||||
|
||||
function = CombinedFunction(
|
||||
'range',
|
||||
Function(_signature1, _function1),
|
||||
Function(_signature2, _function2),
|
||||
Function(_signature3, _function3),
|
||||
Function(_signature4, _function4),
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
from smnp.module.note.function import note
|
||||
from smnp.module.note.function import tuplet, transpose, semitones, octave, duration, interval
|
||||
|
||||
functions = [ note.function ]
|
||||
methods = []
|
||||
functions = [ semitones.function, interval.function, transpose.function, tuplet.function ]
|
||||
methods = [ duration.function, octave.function ]
|
||||
11
smnp/module/note/function/duration.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from smnp.function.model import Function
|
||||
from smnp.function.signature import signature
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.type import ofType
|
||||
|
||||
_signature = signature(ofType(Type.NOTE), ofType(Type.INTEGER))
|
||||
def _function(env, note, duration):
|
||||
return Type.note(note.value.withDuration(duration.value))
|
||||
|
||||
|
||||
function = Function(_signature, _function, 'withDuration')
|
||||
27
smnp/module/note/function/interval.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from smnp.function.model import Function, CombinedFunction
|
||||
from smnp.function.signature import varargSignature
|
||||
from smnp.note.interval import intervalToString
|
||||
from smnp.note.model import Note
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.list import listOf
|
||||
from smnp.type.signature.matcher.type import ofTypes
|
||||
|
||||
_signature1 = varargSignature(ofTypes(Type.NOTE, Type.INTEGER))
|
||||
def _function1(env, vararg):
|
||||
withoutPauses = [note.value for note in vararg if note.type == Type.NOTE]
|
||||
if len(withoutPauses) < 2:
|
||||
return Type.list([])
|
||||
semitones = [Note.checkInterval(withoutPauses[i-1], withoutPauses[i]) for i in range(1, len(withoutPauses))]
|
||||
return Type.list([Type.string(intervalToString(s)) for s in semitones]).decompose()
|
||||
|
||||
|
||||
_signature2 = varargSignature(listOf(Type.NOTE, Type.INTEGER))
|
||||
def _function2(env, vararg):
|
||||
return Type.list([_function1(env, arg.value) for arg in vararg]).decompose()
|
||||
|
||||
|
||||
function = CombinedFunction(
|
||||
'interval',
|
||||
Function(_signature1, _function1),
|
||||
Function(_signature2, _function2)
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
from smnp.function.model import Function
|
||||
from smnp.function.signature import signature
|
||||
from smnp.note.model import Note
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.type import ofType
|
||||
|
||||
_signature = signature(ofType(Type.STRING), ofType(Type.INTEGER), ofType(Type.INTEGER), ofType(Type.BOOL))
|
||||
def _function(env, note, octave, duration, dot):
|
||||
return Type.note(Note(note.value, octave.value, duration.value, dot.value))
|
||||
|
||||
function = Function(_signature, _function, 'Note')
|
||||
11
smnp/module/note/function/octave.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from smnp.function.model import Function
|
||||
from smnp.function.signature import signature
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.type import ofType
|
||||
|
||||
_signature = signature(ofType(Type.NOTE), ofType(Type.INTEGER))
|
||||
def _function(env, note, octave):
|
||||
return Type.note(note.value.withOctave(octave.value))
|
||||
|
||||
|
||||
function = Function(_signature, _function, 'withOctave')
|
||||
25
smnp/module/note/function/semitones.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from smnp.function.model import Function, CombinedFunction
|
||||
from smnp.function.signature import varargSignature
|
||||
from smnp.note.model import Note
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.list import listOf
|
||||
from smnp.type.signature.matcher.type import ofTypes
|
||||
|
||||
_signature1 = varargSignature(ofTypes(Type.NOTE, Type.INTEGER))
|
||||
def _function1(env, vararg):
|
||||
withoutPauses = [note.value for note in vararg if note.type == Type.NOTE]
|
||||
if len(withoutPauses) < 2:
|
||||
return Type.list([])
|
||||
return Type.list([Type.integer(Note.checkInterval(withoutPauses[i-1], withoutPauses[i])) for i in range(1, len(withoutPauses))]).decompose()
|
||||
|
||||
|
||||
_signature2 = varargSignature(listOf(Type.NOTE, Type.INTEGER))
|
||||
def _function2(env, vararg):
|
||||
return Type.list([_function1(env, arg.value) for arg in vararg]).decompose()
|
||||
|
||||
|
||||
function = CombinedFunction(
|
||||
"semitones",
|
||||
Function(_signature1, _function1),
|
||||
Function(_signature2, _function2),
|
||||
)
|
||||
22
smnp/module/note/function/transpose.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from smnp.function.model import CombinedFunction, Function
|
||||
from smnp.function.signature import varargSignature
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.list import listOf
|
||||
from smnp.type.signature.matcher.type import ofTypes
|
||||
|
||||
_signature1 = varargSignature(ofTypes(Type.INTEGER, Type.NOTE), ofTypes(Type.INTEGER))
|
||||
def _function1(env, value, vararg):
|
||||
transposed = [Type.note(arg.value.transpose(value.value)) if arg.type == Type.NOTE else arg for arg in vararg]
|
||||
return Type.list(transposed).decompose()
|
||||
|
||||
|
||||
_signature2 = varargSignature(listOf(Type.INTEGER, Type.NOTE), ofTypes(Type.INTEGER))
|
||||
def _function2(env, value, vararg):
|
||||
return Type.list([_function1(env, value, arg.value) for arg in vararg]).decompose()
|
||||
|
||||
|
||||
function = CombinedFunction(
|
||||
'transpose',
|
||||
Function(_signature1, _function1),
|
||||
Function(_signature2, _function2)
|
||||
)
|
||||
23
smnp/module/note/function/tuplet.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from smnp.function.model import CombinedFunction, Function
|
||||
from smnp.function.signature import signature, varargSignature
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.list import listOf
|
||||
from smnp.type.signature.matcher.type import ofTypes
|
||||
|
||||
_signature1 = varargSignature(ofTypes(Type.NOTE), ofTypes(Type.INTEGER), ofTypes(Type.INTEGER))
|
||||
def _function1(env, n, m, vararg):
|
||||
t = [Type.note(arg.value.withDuration(int(arg.value.duration * n.value / m.value))) for arg in vararg]
|
||||
return Type.list(t).decompose()
|
||||
|
||||
|
||||
|
||||
_signature2 = signature(ofTypes(Type.INTEGER), ofTypes(Type.INTEGER), listOf(Type.NOTE))
|
||||
def _function2(env, n, m, notes):
|
||||
return _function1(env, n, m, notes.value)
|
||||
|
||||
|
||||
function = CombinedFunction(
|
||||
'tuplet',
|
||||
Function(_signature1, _function1),
|
||||
Function(_signature2, _function2)
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
from smnp.module.string.function import stringify
|
||||
from smnp.module.string.function import concat
|
||||
|
||||
functions = []
|
||||
methods = [ stringify.function ]
|
||||
functions = [ concat.function ]
|
||||
methods = []
|
||||
11
smnp/module/string/function/concat.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from smnp.function.model import Function
|
||||
from smnp.function.signature import varargSignature
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.type import ofType
|
||||
|
||||
_signature = varargSignature(ofType(Type.STRING))
|
||||
def _function(env, vararg):
|
||||
return Type.string("".join([ arg.value for arg in vararg ]))
|
||||
|
||||
|
||||
function = Function(_signature, _function, 'concat')
|
||||
@@ -1,10 +0,0 @@
|
||||
from smnp.function.model import Function
|
||||
from smnp.function.signature import signature
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.signature.matcher.type import allTypes
|
||||
|
||||
_signature = signature(allTypes())
|
||||
def _function(env, object):
|
||||
return Type.string(object.stringify())
|
||||
|
||||
function = Function(_signature, _function, 'toString')
|
||||
@@ -1,4 +1,4 @@
|
||||
from smnp.module.synth.function import synth, pause, plot, compile, fft
|
||||
from smnp.module.synth.function import synth, pause
|
||||
|
||||
functions = [ synth.function, pause.function, plot.function, compile.function, fft.function ]
|
||||
functions = [ synth.function, pause.function ]
|
||||
methods = []
|
||||