Improve library
This commit is contained in:
@@ -1,44 +1,60 @@
|
||||
import smnp.environment.function.list as l
|
||||
from smnp.environment.environment import Environment
|
||||
from smnp.environment.function import synth, base, interval, note, transposer, rand, mic
|
||||
from smnp.environment.function.model import Function, ONLY_FUNCTION
|
||||
from smnp.note.model import Note
|
||||
from smnp.library.function.combine import combine
|
||||
from smnp.library.function.display import display
|
||||
from smnp.library.function.exit import exit
|
||||
from smnp.library.function.flat import flat
|
||||
from smnp.library.function.interval import interval
|
||||
from smnp.library.function.semitones import semitones
|
||||
from smnp.library.function.sleep import sleep
|
||||
from smnp.library.function.type import objectType
|
||||
|
||||
|
||||
def createEnvironment():
|
||||
functions = {
|
||||
'exit': Function(base.exit, ONLY_FUNCTION),
|
||||
'print': Function(base.display, ONLY_FUNCTION),
|
||||
'read': Function(base.read, ONLY_FUNCTION),
|
||||
'type': Function(base.objectType, ONLY_FUNCTION),
|
||||
'sleep': Function(base.sleep, ONLY_FUNCTION),
|
||||
'synth': Function(synth.synth, ONLY_FUNCTION),
|
||||
'pause': Function(synth.pause, ONLY_FUNCTION),
|
||||
'changeDuration': Function(note.changeDuration, ONLY_FUNCTION),
|
||||
'changeOctave': Function(note.changeOctave, ONLY_FUNCTION),
|
||||
'semitones': Function(interval.semitones, ONLY_FUNCTION),
|
||||
'interval': Function(interval.interval, ONLY_FUNCTION),
|
||||
'transpose': Function(transposer.transpose, ONLY_FUNCTION),
|
||||
'transposeTo': Function(transposer.transposeTo, ONLY_FUNCTION),
|
||||
'random': Function(rand.random, ONLY_FUNCTION),
|
||||
# 'sample': sample,
|
||||
'wait': Function(mic.wait, ONLY_FUNCTION),
|
||||
'tuplet': Function(note.tuplet, ONLY_FUNCTION),
|
||||
'combine': Function(l.combine, ONLY_FUNCTION),
|
||||
'flat': Function(l.flat, ONLY_FUNCTION),
|
||||
'debug': Function(lambda args, env: print(args), ONLY_FUNCTION),
|
||||
functions = [
|
||||
display,
|
||||
objectType,
|
||||
exit,
|
||||
sleep,
|
||||
semitones,
|
||||
interval,
|
||||
combine,
|
||||
flat
|
||||
]
|
||||
|
||||
}
|
||||
methods = [
|
||||
|
||||
methods = {
|
||||
str: {},
|
||||
list: {},
|
||||
float: {},
|
||||
Note: {
|
||||
'synth': synth.synth
|
||||
},
|
||||
type(None): {},
|
||||
}
|
||||
]
|
||||
# 'exit': Function(base.exit, ONLY_FUNCTION),
|
||||
# 'print': Function(base.display, ONLY_FUNCTION),
|
||||
# 'read': Function(base.read, ONLY_FUNCTION),
|
||||
# 'type': Function(base.objectType, ONLY_FUNCTION),
|
||||
# 'sleep': Function(base.sleep, ONLY_FUNCTION),
|
||||
# 'synth': Function(synth.synth, ONLY_FUNCTION),
|
||||
# 'pause': Function(synth.pause, ONLY_FUNCTION),
|
||||
# 'changeDuration': Function(note.changeDuration, ONLY_FUNCTION),
|
||||
# 'changeOctave': Function(note.changeOctave, ONLY_FUNCTION),
|
||||
# 'semitones': Function(interval.semitones, ONLY_FUNCTION),
|
||||
# 'interval': Function(interval.interval, ONLY_FUNCTION),
|
||||
# 'transpose': Function(transposer.transpose, ONLY_FUNCTION),
|
||||
# 'transposeTo': Function(transposer.transposeTo, ONLY_FUNCTION),
|
||||
# 'random': Function(rand.random, ONLY_FUNCTION),
|
||||
# # 'sample': sample,
|
||||
# 'wait': Function(mic.wait, ONLY_FUNCTION),
|
||||
# 'tuplet': Function(note.tuplet, ONLY_FUNCTION),
|
||||
# 'combine': Function(l.combine, ONLY_FUNCTION),
|
||||
# 'flat': Function(l.flat, ONLY_FUNCTION),
|
||||
# 'debug': Function(lambda args, env: print(args), ONLY_FUNCTION),
|
||||
|
||||
|
||||
# methods = {
|
||||
# str: {},
|
||||
# list: {},
|
||||
# float: {},
|
||||
# Note: {
|
||||
# 'synth': synth.synth
|
||||
# },
|
||||
# type(None): {},
|
||||
# }
|
||||
|
||||
variables = {
|
||||
"bpm": 120
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
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
|
||||
22
smnp/library/function/combine.py
Normal file
22
smnp/library/function/combine.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from functools import reduce
|
||||
|
||||
from smnp.library.model import Function
|
||||
from smnp.library.signature import varargSignature, ofTypes
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.value import Value
|
||||
|
||||
|
||||
def _combine(env, vararg):
|
||||
if len(vararg) == 1:
|
||||
return vararg[0]
|
||||
|
||||
combined = reduce(lambda x, y: x.value + y.value, vararg)
|
||||
return Value(Type.LIST, combined)
|
||||
|
||||
|
||||
|
||||
_sign = varargSignature(ofTypes(Type.LIST))
|
||||
|
||||
|
||||
combine = Function(_sign, _combine, 'combine')
|
||||
|
||||
10
smnp/library/function/display.py
Normal file
10
smnp/library/function/display.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from smnp.library.model import Function
|
||||
from smnp.library.signature import varargSignature, allTypes
|
||||
|
||||
|
||||
def _display(env, vararg):
|
||||
print("".join([arg.stringify() for arg in vararg]))
|
||||
|
||||
_sign = varargSignature(allTypes())
|
||||
|
||||
display = Function(_sign, _display, 'print')
|
||||
13
smnp/library/function/exit.py
Normal file
13
smnp/library/function/exit.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
|
||||
from smnp.library.model import Function
|
||||
from smnp.library.signature import signature, ofTypes
|
||||
from smnp.type.model import Type
|
||||
|
||||
|
||||
def _exit(env, code):
|
||||
sys.exit(code.value)
|
||||
|
||||
_sign = signature(ofTypes(Type.INTEGER))
|
||||
|
||||
exit = Function(_sign, _exit, 'exit')
|
||||
21
smnp/library/function/flat.py
Normal file
21
smnp/library/function/flat.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from smnp.library.model import Function
|
||||
from smnp.library.signature import varargSignature, allTypes
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.value import Value
|
||||
|
||||
|
||||
def _flat(env, vararg):
|
||||
return Value(Type.LIST, doFlat(vararg, [])).decompose()
|
||||
|
||||
def doFlat(input, output=[]):
|
||||
for item in input:
|
||||
if item.type == Type.LIST:
|
||||
doFlat(item.value, output)
|
||||
else:
|
||||
output.append(item)
|
||||
return output
|
||||
|
||||
|
||||
_sign = varargSignature(allTypes())
|
||||
|
||||
flat = Function(_sign, _flat, 'flat')
|
||||
@@ -1,27 +1,30 @@
|
||||
from smnp.library.tools import returnElementOrList
|
||||
from smnp.library.model import Function, CombinedFunction
|
||||
from smnp.library.signature import varargSignature, ofTypes, listOf
|
||||
from smnp.note.interval import intervalToString
|
||||
from smnp.note.model import Note
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.value import Value
|
||||
|
||||
|
||||
def interval(args, env):
|
||||
if len(args) > 0 and isinstance(args[0], list):
|
||||
return intervalList(args[0])
|
||||
return intervalList(args)
|
||||
def _interval1(env, vararg):
|
||||
withoutPauses = [note.value for note in vararg if note.type == Type.NOTE]
|
||||
if len(withoutPauses) < 2:
|
||||
return Value(Type.LIST, [])
|
||||
semitones = [Note.checkInterval(withoutPauses[i-1], withoutPauses[i]) for i in range(1, len(withoutPauses))]
|
||||
return Value(Type.LIST, [Value(Type.STRING, intervalToString(s)) for s in semitones]).decompose()
|
||||
|
||||
|
||||
def intervalList(list):
|
||||
r = [intervalToString(x) for x in semitonesList(list)]
|
||||
return returnElementOrList(r)
|
||||
_sign1 = varargSignature(ofTypes(Type.NOTE, Type.INTEGER))
|
||||
|
||||
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))
|
||||
def _interval2(env, vararg):
|
||||
return Value(Type.LIST, [_interval1(env, arg.value) for arg in vararg]).decompose()
|
||||
|
||||
_sign2 = varargSignature(listOf(Type.NOTE, Type.INTEGER))
|
||||
|
||||
|
||||
interval = CombinedFunction(
|
||||
'interval',
|
||||
Function(_sign1, _interval1),
|
||||
Function(_sign2, _interval2)
|
||||
)
|
||||
@@ -1,19 +0,0 @@
|
||||
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
|
||||
28
smnp/library/function/read.py
Normal file
28
smnp/library/function/read.py
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
# TODO read function
|
||||
# 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
|
||||
29
smnp/library/function/semitones.py
Normal file
29
smnp/library/function/semitones.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from smnp.library.model import Function, CombinedFunction
|
||||
from smnp.library.signature import varargSignature, ofTypes, listOf
|
||||
from smnp.note.model import Note
|
||||
from smnp.type.model import Type
|
||||
from smnp.type.value import Value
|
||||
|
||||
|
||||
def _semitones1(env, vararg):
|
||||
withoutPauses = [note.value for note in vararg if note.type == Type.NOTE]
|
||||
if len(withoutPauses) < 2:
|
||||
return Value(Type.LIST, [])
|
||||
return Value(Type.LIST, [Value(Type.INTEGER, Note.checkInterval(withoutPauses[i-1], withoutPauses[i])) for i in range(1, len(withoutPauses))]).decompose()
|
||||
|
||||
|
||||
_sign1 = varargSignature(ofTypes(Type.NOTE, Type.INTEGER))
|
||||
|
||||
|
||||
def _semitones2(env, vararg):
|
||||
return Value(Type.LIST, [_semitones1(env, arg.value) for arg in vararg]).decompose()
|
||||
|
||||
|
||||
_sign2 = varargSignature(listOf(Type.NOTE, Type.INTEGER))
|
||||
|
||||
|
||||
semitones = CombinedFunction(
|
||||
"semitones",
|
||||
Function(_sign1, _semitones1),
|
||||
Function(_sign2, _semitones2),
|
||||
)
|
||||
13
smnp/library/function/sleep.py
Normal file
13
smnp/library/function/sleep.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import time
|
||||
|
||||
from smnp.library.model import Function
|
||||
from smnp.library.signature import ofTypes, signature
|
||||
from smnp.type.model import Type
|
||||
|
||||
|
||||
def _sleep(env, value):
|
||||
time.sleep(value.value)
|
||||
|
||||
_sign = signature(ofTypes(Type.INTEGER))
|
||||
|
||||
sleep = Function(_sign, _sleep, 'sleep')
|
||||
@@ -1,5 +1,6 @@
|
||||
from smnp.library.function.interval import semitonesList
|
||||
from smnp.library.tools import returnElementOrList
|
||||
|
||||
from smnp.library.function.semitones import semitonesList
|
||||
from smnp.note.model import Note
|
||||
|
||||
|
||||
|
||||
10
smnp/library/function/type.py
Normal file
10
smnp/library/function/type.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from smnp.library.model import Function
|
||||
from smnp.library.signature import signature, allTypes
|
||||
|
||||
|
||||
def _objectType(env, obj):
|
||||
return obj.type.name
|
||||
|
||||
_sign = signature(allTypes())
|
||||
|
||||
objectType = Function(_sign, _objectType, 'type')
|
||||
@@ -11,7 +11,7 @@ class FunctionType(Enum):
|
||||
|
||||
|
||||
class Function:
|
||||
def __init__(self, name, signature, function):
|
||||
def __init__(self, signature, function, name=None):
|
||||
self.name = name
|
||||
self.signature = signature
|
||||
self.function = function
|
||||
@@ -25,6 +25,7 @@ class Function:
|
||||
ret = self.function(env, *result[1:])
|
||||
if ret is None:
|
||||
return Value(Type.VOID, None)
|
||||
return ret
|
||||
raise IllegalFunctionInvocationException(self.stringSignature(), f"{self.name}{types(args)}") #TODO: argumenty do typów, nie wartości
|
||||
|
||||
|
||||
@@ -44,6 +45,7 @@ class CombinedFunction(Function):
|
||||
ret = function.function(env, *result[1:])
|
||||
if ret is None:
|
||||
return Value(Type.VOID, None)
|
||||
return ret
|
||||
raise IllegalFunctionInvocationException(self.stringSignature(), f"{self.name}{types(args)}")
|
||||
|
||||
|
||||
|
||||
@@ -84,6 +84,11 @@ def doesNotMatch(sign):
|
||||
return (False, *[None for n in sign])
|
||||
|
||||
|
||||
def allTypes():
|
||||
allowedTypes = [t for t in Type if t != Type.VOID]
|
||||
return ofTypes(*allowedTypes)
|
||||
|
||||
|
||||
def ofTypes(*types):
|
||||
def check(value):
|
||||
return value.type in types
|
||||
@@ -103,7 +108,6 @@ def listMatches(*pattern):
|
||||
|
||||
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}")
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
def returnElementOrList(list):
|
||||
return list[0] if len(list) == 1 else list
|
||||
@@ -2,4 +2,4 @@ from smnp.token.tools import tokenizeKeyword
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
def tokenizeFunction(input, current, line):
|
||||
return tokenizeKeyword(TokenType.FUNCTION, 'function', input, current, line)
|
||||
return tokenizeKeyword(TokenType.FUNCTION, 'library', input, current, line)
|
||||
|
||||
@@ -10,14 +10,14 @@ class Type(Enum):
|
||||
LIST = (list, lambda x: f"({', '.join([e.stringify() for e in x])})")
|
||||
PERCENT = (float, lambda x: f"{int(x * 100)}%")
|
||||
NOTE = (Note, lambda x: x.note.name)
|
||||
VOID = (type(None), lambda x: _failStringify(x))
|
||||
VOID = (type(None), lambda x: _failStringify(Type.VOID))
|
||||
|
||||
def stringify(self, element):
|
||||
return self.value[1](element)
|
||||
|
||||
|
||||
def _failStringify(obj):
|
||||
raise RuntimeException(None, f"Not able to interpret '{obj.type.name()}'")
|
||||
def _failStringify(t):
|
||||
raise RuntimeException(None, f"Not able to interpret {t.name}'")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +1,33 @@
|
||||
from smnp.type.model import Type
|
||||
|
||||
|
||||
class Value:
|
||||
def __init__(self, objectType, value):
|
||||
self.value = value
|
||||
|
||||
if type(value) == objectType.value[0]:
|
||||
self.type = objectType
|
||||
|
||||
elif type(value) == Value:
|
||||
raise RuntimeError("Trying to pass object of 'Value' type as value of it")
|
||||
|
||||
else:
|
||||
raise RuntimeError(f"Invalid type '{objectType.name}' for value '{value}'")
|
||||
|
||||
def stringify(self):
|
||||
return self.type.stringify(self.value)
|
||||
|
||||
def decompose(self):
|
||||
if self.type != Type.LIST:
|
||||
raise RuntimeError(f"Method 'decompose' can be applied only for lists")
|
||||
|
||||
if len(self.value) == 1:
|
||||
return Value(self.value[0].type, self.value[0].value)
|
||||
|
||||
return self
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.type.name}({self.stringify()})"
|
||||
return f"{self.type.name}({self.value})"
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
Reference in New Issue
Block a user