Improve environment #1
This commit is contained in:
0
smnp/library/__init__.py
Normal file
0
smnp/library/__init__.py
Normal file
0
smnp/library/function/__init__.py
Normal file
0
smnp/library/function/__init__.py
Normal file
55
smnp/library/function/base.py
Normal file
55
smnp/library/function/base.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
def display(args, env):
|
||||
print("".join([arg.stringify() for arg in args]))
|
||||
|
||||
|
||||
def objectType(args, env):
|
||||
if len(args) == 1:
|
||||
return args[0].stringify()
|
||||
else:
|
||||
pass # not valid signature
|
||||
|
||||
|
||||
def exit(args, env):
|
||||
if len(args) == 1 and isinstance(args[0], int):
|
||||
sys.exit(args[0])
|
||||
else:
|
||||
pass # not valid signature
|
||||
|
||||
|
||||
def sleep(args, env):
|
||||
if len(args) == 1 and isinstance(args[0], int):
|
||||
time.sleep(args[0])
|
||||
else:
|
||||
pass # not valid signature
|
||||
|
||||
|
||||
def read(args, env):
|
||||
if len(args) == 2 and isinstance(args[0], str) and isinstance(args[1], str):
|
||||
print(args[0], end="")
|
||||
value = input()
|
||||
if args[1] == "integer":
|
||||
try:
|
||||
return int(value)
|
||||
except ValueError as v:
|
||||
pass # not int
|
||||
elif args[1] == "string":
|
||||
return value
|
||||
# TODO: note - wydzielić parsowanie nut do osobnej funkcji w pakiecie smnp.note
|
||||
# elif args[1] == "note":
|
||||
# chars, token = tokenizeNote(value, 0, 0)
|
||||
# if chars == 0:
|
||||
# return # not note
|
||||
# return parseNote([token], None).value
|
||||
else:
|
||||
pass # invalid type
|
||||
elif len(args) == 1 and isinstance(args[0], str):
|
||||
print(args[0], end="")
|
||||
return input()
|
||||
elif len(args) == 0:
|
||||
return input()
|
||||
else:
|
||||
pass # not valid signature
|
||||
27
smnp/library/function/interval.py
Normal file
27
smnp/library/function/interval.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from smnp.library.tools import returnElementOrList
|
||||
from smnp.note.interval import intervalToString
|
||||
from smnp.note.model import Note
|
||||
|
||||
|
||||
def interval(args, env):
|
||||
if len(args) > 0 and isinstance(args[0], list):
|
||||
return intervalList(args[0])
|
||||
return intervalList(args)
|
||||
|
||||
|
||||
def intervalList(list):
|
||||
r = [intervalToString(x) for x in semitonesList(list)]
|
||||
return returnElementOrList(r)
|
||||
|
||||
def semitonesList(list):
|
||||
for x in list:
|
||||
if not isinstance(x, Note) and not isinstance(x, int):
|
||||
pass # invalid arguments
|
||||
withoutPauses = tuple(filter(lambda x: isinstance(x, Note), list))
|
||||
r = [Note.checkInterval(withoutPauses[i-1], withoutPauses[i]) for i, _ in enumerate(withoutPauses) if i != 0]
|
||||
return r
|
||||
|
||||
def semitones(args, env):
|
||||
if len(args) > 0 and isinstance(args[0], list):
|
||||
return returnElementOrList(semitonesList(args[0]))
|
||||
return returnElementOrList(semitonesList(args))
|
||||
19
smnp/library/function/list.py
Normal file
19
smnp/library/function/list.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from functools import reduce
|
||||
|
||||
|
||||
def combine(args, env):
|
||||
if all(type(x) == list for x in args):
|
||||
return reduce((lambda x, y: x + y), args)
|
||||
|
||||
|
||||
def flat(args, env):
|
||||
return _flat(args, [])
|
||||
|
||||
|
||||
def _flat(input, output = []):
|
||||
for item in input:
|
||||
if type(item) == list:
|
||||
_flat(item, output)
|
||||
else:
|
||||
output.append(item)
|
||||
return output
|
||||
3
smnp/library/function/mic.py
Normal file
3
smnp/library/function/mic.py
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
def wait(args, env):
|
||||
pass
|
||||
31
smnp/library/function/note.py
Normal file
31
smnp/library/function/note.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from smnp.library.tools import returnElementOrList
|
||||
|
||||
|
||||
def changeDuration(args, env):
|
||||
if len(args) == 2 and isinstance(args[0], Note) and isinstance(args[1], int):
|
||||
return args[0].withDuration(args[1])
|
||||
return # invalid signature
|
||||
|
||||
|
||||
def changeOctave(args, env):
|
||||
if len(args) == 2 and isinstance(args[0], Note) and isinstance(args[1], int):
|
||||
return args[0].withOctave(args[1])
|
||||
return # invalid signature
|
||||
|
||||
|
||||
def tupletList(n, m, list):
|
||||
return [note.withDuration(note.duration * n / m) for note in list]
|
||||
|
||||
|
||||
def tuplet(args, env):
|
||||
if len(args) > 2 and type(args[0]) == int and type(args[1]) == int and all(type(x) == Note for x in args[2:]):
|
||||
n = args[0] # how many notes
|
||||
m = args[1] # instead of number of notes (3-tuplet: 3 instead 2; 5-tuplet: 5 instead 4 etc.)
|
||||
return returnElementOrList(tupletList(n, m, args[2:]))
|
||||
elif len(args) == 3 and type(args[0]) == int and type(args[1]) == int and type(args[2]) == list and all(type(x) == Note for x in args[2]):
|
||||
n = args[0]
|
||||
m = args[1]
|
||||
l = args[2]
|
||||
return returnElementOrList(tupletList(n, m, l))
|
||||
else:
|
||||
pass # not valid signature
|
||||
17
smnp/library/function/rand.py
Normal file
17
smnp/library/function/rand.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import random as r
|
||||
|
||||
|
||||
def random(args, env):
|
||||
if not all(isinstance(x, list) and len(x) == 2 and isinstance(x[0], float) for x in args):
|
||||
return # not valid signature
|
||||
if sum([x[0] for x in args]) != 1.0:
|
||||
return # not sums to 100%
|
||||
choice = r.random()
|
||||
acc = 0
|
||||
for e in args:
|
||||
acc += e[0]
|
||||
if choice <= acc:
|
||||
return e[1]
|
||||
|
||||
|
||||
#TODO: sample
|
||||
6
smnp/library/function/synth.py
Normal file
6
smnp/library/function/synth.py
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
def synth(args, env):
|
||||
pass
|
||||
|
||||
def pause(args, env):
|
||||
pass
|
||||
41
smnp/library/function/transposer.py
Normal file
41
smnp/library/function/transposer.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from smnp.library.function.interval import semitonesList
|
||||
from smnp.library.tools import returnElementOrList
|
||||
from smnp.note.model import Note
|
||||
|
||||
|
||||
def transposeTo(args, env):
|
||||
if len(args) > 1 and isinstance(args[0], Note) and all(isinstance(x, list) for i, x in enumerate(args) if i != 0):
|
||||
target = args[0]
|
||||
result = []
|
||||
for i, notes in enumerate(args):
|
||||
if i == 0:
|
||||
continue
|
||||
if len(notes) > 0:
|
||||
first = notes[0]
|
||||
semitones = semitonesList([first, target])[0]
|
||||
result.append([note.transpose(semitones) for note in notes if isinstance(note, Note)])
|
||||
else:
|
||||
result.append([])
|
||||
return returnElementOrList(result)
|
||||
else:
|
||||
pass # not valid signature
|
||||
|
||||
|
||||
def transpose(args, env):
|
||||
if len(args) > 1 and isinstance(args[0], int) and all(
|
||||
isinstance(arg, list) for i, arg in enumerate(args) if i != 0):
|
||||
value = args[0]
|
||||
transposed = []
|
||||
for i, arg in enumerate(args):
|
||||
if i == 0:
|
||||
continue
|
||||
if not isinstance(arg, list):
|
||||
return # is not list
|
||||
transposed.append([note.transpose(value) for note in arg if isinstance(note, Note)])
|
||||
return returnElementOrList(transposed)
|
||||
if len(args) > 1 and all(isinstance(arg, Note) for i, arg in enumerate(args) if i != 0):
|
||||
value = args[0]
|
||||
transposed = [note.transpose(value) for i, note in enumerate(args) if i != 0]
|
||||
return returnElementOrList(transposed)
|
||||
else:
|
||||
return # not valid signature
|
||||
66
smnp/library/model.py
Normal file
66
smnp/library/model.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from enum import Enum, auto
|
||||
|
||||
from smnp.error.function import IllegalFunctionInvocationException
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.value import Value
|
||||
|
||||
|
||||
class FunctionType(Enum):
|
||||
FUNCTION = auto()
|
||||
METHOD = auto()
|
||||
|
||||
|
||||
class Function:
|
||||
def __init__(self, name, signature, function):
|
||||
self.name = name
|
||||
self.signature = signature
|
||||
self.function = function
|
||||
|
||||
def stringSignature(self):
|
||||
return f"{self.name}{self.signature.string}"
|
||||
|
||||
def call(self, env, args):
|
||||
result = self.signature.check(args)
|
||||
if result[0]:
|
||||
ret = self.function(env, *result[1:])
|
||||
if ret is None:
|
||||
return Value(Type.VOID, None)
|
||||
raise IllegalFunctionInvocationException(self.stringSignature(), f"{self.name}{types(args)}") #TODO: argumenty do typów, nie wartości
|
||||
|
||||
|
||||
class CombinedFunction(Function):
|
||||
def __init__(self, name, *functions):
|
||||
super().__init__(None, None, None)
|
||||
self.name = name
|
||||
self.functions = functions
|
||||
|
||||
def stringSignature(self):
|
||||
return "\nor\n".join([f"{self.name}{function.signature.string}" for function in self.functions])
|
||||
|
||||
def call(self, env, args):
|
||||
for function in self.functions:
|
||||
result = function.signature.check(args)
|
||||
if result[0]:
|
||||
ret = function.function(env, *result[1:])
|
||||
if ret is None:
|
||||
return Value(Type.VOID, None)
|
||||
raise IllegalFunctionInvocationException(self.stringSignature(), f"{self.name}{types(args)}")
|
||||
|
||||
|
||||
def types(args):
|
||||
output = []
|
||||
for arg in args:
|
||||
if arg.type == Type.LIST:
|
||||
output.append(listTypes(arg.value, []))
|
||||
else:
|
||||
output.append(arg.type.name)
|
||||
return f"({', '.join(output)})"
|
||||
|
||||
|
||||
def listTypes(l, output=[]):
|
||||
for item in l:
|
||||
if item.type == Type.LIST:
|
||||
output.append(listTypes(item.value, []))
|
||||
else:
|
||||
output.append(item.type.name)
|
||||
return f"LIST<{'|'.join(set(output))}>"
|
||||
118
smnp/library/signature.py
Normal file
118
smnp/library/signature.py
Normal file
@@ -0,0 +1,118 @@
|
||||
# from smnp.type.model import Type
|
||||
#
|
||||
from smnp.type.model import Type
|
||||
|
||||
|
||||
class Matcher:
|
||||
def __init__(self, objectType, matcher, string):
|
||||
self.type = objectType
|
||||
self.matcher = matcher
|
||||
self.string = string
|
||||
|
||||
def match(self, value):
|
||||
if self.type is not None and self.type != value.type:
|
||||
return False
|
||||
return self.matcher(value)
|
||||
|
||||
def andWith(self, matcher):
|
||||
if self.type != matcher.type:
|
||||
raise RuntimeError("Support types of matches are not the same")
|
||||
string = f"[{self.string} and {matcher.string}]"
|
||||
return Matcher(self.type, lambda x: self.match(x) and matcher.match(x), string)
|
||||
|
||||
def orWith(self, matcher):
|
||||
string = f"[{self.string} or {matcher.string}]"
|
||||
return Matcher(None, lambda x: self.match(x) or matcher.match(x), string)
|
||||
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self.string
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
|
||||
class Signature:
|
||||
def __init__(self, check, string):
|
||||
self.check = check
|
||||
self.string = string
|
||||
|
||||
|
||||
def varargSignature(varargMatcher, *basicSignature):
|
||||
def check(args):
|
||||
if len(basicSignature) > len(args):
|
||||
return doesNotMatchVararg(basicSignature)
|
||||
|
||||
for i in range(len(basicSignature)):
|
||||
if not basicSignature[i].match(args[i]):
|
||||
return doesNotMatchVararg(basicSignature)
|
||||
|
||||
for i in range(len(basicSignature), len(args)):
|
||||
if not varargMatcher.match(args[i]):
|
||||
return doesNotMatchVararg(basicSignature)
|
||||
|
||||
return True, (*args[:len(basicSignature)]), args[len(basicSignature):]
|
||||
|
||||
string = f"({', '.join([str(m) for m in basicSignature])}{', ' if len(basicSignature) > 0 else ''}{str(varargMatcher)}...)"
|
||||
|
||||
return Signature(check, string)
|
||||
|
||||
|
||||
def doesNotMatchVararg(basicSignature):
|
||||
return (False, *[None for n in basicSignature], None)
|
||||
#
|
||||
|
||||
|
||||
def signature(*signature):
|
||||
def check(args):
|
||||
if len(signature) != len(args):
|
||||
return doesNotMatch(signature)
|
||||
|
||||
for s, a in zip(signature, args):
|
||||
if not s.match(a):
|
||||
return doesNotMatch(signature)
|
||||
|
||||
return (True, *args)
|
||||
|
||||
string = f"({', '.join([str(m) for m in signature])})"
|
||||
|
||||
return Signature(check, string)
|
||||
|
||||
|
||||
def doesNotMatch(sign):
|
||||
return (False, *[None for n in sign])
|
||||
|
||||
|
||||
def ofTypes(*types):
|
||||
def check(value):
|
||||
return value.type in types
|
||||
return Matcher(None, check, f"<{'|'.join([t.name for t in types])}>")
|
||||
|
||||
|
||||
def listOf(*types):
|
||||
def check(value):
|
||||
return len([item for item in value.value if not item.type in types]) == 0
|
||||
|
||||
return Matcher(Type.LIST, check, f"{Type.LIST.name}<{'|'.join([t.name for t in types])}>")
|
||||
|
||||
|
||||
def listMatches(*pattern):
|
||||
def check(value):
|
||||
return signature(*pattern).check(value.value)[0]
|
||||
|
||||
return Matcher(Type.LIST, check, f"({', '.join([str(m) for m in pattern])})")
|
||||
|
||||
|
||||
def recursiveListMatcher(matcher):
|
||||
if matcher.type == Type.LIST:
|
||||
raise RuntimeError(f"Passed matcher will be handling non-list types, so it cannot have type set to {Type.LIST}")
|
||||
|
||||
def check(value):
|
||||
if value.type != Type.LIST:
|
||||
return matcher.match(value)
|
||||
for item in value.value:
|
||||
return check(item)
|
||||
|
||||
return Matcher(Type.LIST, check, f"[LISTS OF {str(matcher)}]")
|
||||
|
||||
2
smnp/library/tools.py
Normal file
2
smnp/library/tools.py
Normal file
@@ -0,0 +1,2 @@
|
||||
def returnElementOrList(list):
|
||||
return list[0] if len(list) == 1 else list
|
||||
Reference in New Issue
Block a user