Merge branch 'add-filtering-clause-to-loop-operator'
This commit is contained in:
@@ -78,8 +78,18 @@ def AtomParser(input):
|
|||||||
from smnp.ast.node.identifier import IdentifierParser
|
from smnp.ast.node.identifier import IdentifierParser
|
||||||
from smnp.ast.node.list import ListParser
|
from smnp.ast.node.list import ListParser
|
||||||
from smnp.ast.node.map import MapParser
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
return Parser.oneOf(
|
return Parser.oneOf(
|
||||||
|
parentheses,
|
||||||
LiteralParser,
|
LiteralParser,
|
||||||
IdentifierParser,
|
IdentifierParser,
|
||||||
ListParser,
|
ListParser,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class Or(BinaryOperator):
|
|||||||
class Loop(BinaryOperator):
|
class Loop(BinaryOperator):
|
||||||
def __init__(self, pos):
|
def __init__(self, pos):
|
||||||
super().__init__(pos)
|
super().__init__(pos)
|
||||||
self.children.append(NoneNode())
|
self.children.extend([NoneNode(), NoneNode()])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parameters(self):
|
def parameters(self):
|
||||||
@@ -35,13 +35,22 @@ class Loop(BinaryOperator):
|
|||||||
def parameters(self, value):
|
def parameters(self, value):
|
||||||
self[3] = value
|
self[3] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def filter(self):
|
||||||
|
return self[4]
|
||||||
|
|
||||||
|
@filter.setter
|
||||||
|
def filter(self, value):
|
||||||
|
self[4] = value
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def loop(cls, left, parameters, operator, right):
|
def loop(cls, left, parameters, operator, right, filter):
|
||||||
node = cls(left.pos)
|
node = cls(left.pos)
|
||||||
node.left = left
|
node.left = left
|
||||||
node.parameters = parameters
|
node.parameters = parameters
|
||||||
node.operator = operator
|
node.operator = operator
|
||||||
node.right = right
|
node.right = right
|
||||||
|
node.filter = filter
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
|
||||||
@@ -94,11 +103,19 @@ def LoopParser(input):
|
|||||||
name="loop 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(
|
return Parser.allOf(
|
||||||
ExpressionWithoutLoopParser,
|
ExpressionWithoutLoopParser,
|
||||||
Parser.optional(loopParameters),
|
Parser.optional(loopParameters),
|
||||||
Parser.terminal(TokenType.DASH, createNode=Operator.withValue),
|
Parser.terminal(TokenType.DASH, createNode=Operator.withValue),
|
||||||
StatementParser,
|
StatementParser,
|
||||||
|
Parser.optional(loopFilter),
|
||||||
createNode=Loop.loop,
|
createNode=Loop.loop,
|
||||||
name="dash-loop"
|
name="dash-loop"
|
||||||
)(input)
|
)(input)
|
||||||
|
|||||||
@@ -11,26 +11,11 @@ class Power(BinaryOperator):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def FactorParser(input):
|
def FactorParser(input):
|
||||||
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"
|
|
||||||
)
|
|
||||||
|
|
||||||
factorOperands = Parser.oneOf(
|
|
||||||
parentheses,
|
|
||||||
UnitParser,
|
|
||||||
name="factor operands"
|
|
||||||
)
|
|
||||||
|
|
||||||
powerFactor = Parser.leftAssociativeOperatorParser(
|
powerFactor = Parser.leftAssociativeOperatorParser(
|
||||||
factorOperands,
|
UnitParser,
|
||||||
[TokenType.DOUBLE_ASTERISK],
|
[TokenType.DOUBLE_ASTERISK],
|
||||||
factorOperands,
|
UnitParser,
|
||||||
lambda left, op, right: Power.withValues(left, op, right),
|
lambda left, op, right: Power.withValues(left, op, right),
|
||||||
name="power operator"
|
name="power operator"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class Environment():
|
|||||||
if function.name == name:
|
if function.name == name:
|
||||||
signatureCheckresult = function.signature.check(args)
|
signatureCheckresult = function.signature.check(args)
|
||||||
if signatureCheckresult[0]:
|
if signatureCheckresult[0]:
|
||||||
self.scopes.append(function.defaultArgs)
|
self.appendScope(function.defaultArgs)
|
||||||
self.scopes[-1].update({ argName: argValue for argName, argValue in zip(function.arguments, list(signatureCheckresult[1:])) })
|
self.scopes[-1].update({ argName: argValue for argName, argValue in zip(function.arguments, list(signatureCheckresult[1:])) })
|
||||||
self.callStack.append(CallStackItem(name))
|
self.callStack.append(CallStackItem(name))
|
||||||
result = Type.void()
|
result = Type.void()
|
||||||
@@ -90,7 +90,7 @@ class Environment():
|
|||||||
except Return as r:
|
except Return as r:
|
||||||
result = r.value
|
result = r.value
|
||||||
self.callStack.pop(-1)
|
self.callStack.pop(-1)
|
||||||
self.scopes.pop(-1)
|
self.popScope(mergeVariables=False)
|
||||||
return (True, result)
|
return (True, result)
|
||||||
raise IllegalFunctionInvocationException(f"{function.name}{function.signature.string}", f"{name}{argsTypesToString(args)}")
|
raise IllegalFunctionInvocationException(f"{function.name}{function.signature.string}", f"{name}{argsTypesToString(args)}")
|
||||||
return (False, None)
|
return (False, None)
|
||||||
@@ -140,6 +140,17 @@ class Environment():
|
|||||||
else:
|
else:
|
||||||
return scope
|
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 scopesToString(self):
|
def scopesToString(self):
|
||||||
return "Scopes:\n" + ("\n".join([ f" [{i}]: {scope}" for i, scope in enumerate(self.scopes) ]))
|
return "Scopes:\n" + ("\n".join([ f" [{i}]: {scope}" for i, scope in enumerate(self.scopes) ]))
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from smnp.module.iterable.function import combine, map, get
|
from smnp.module.iterable.function import map, get
|
||||||
|
|
||||||
functions = [ combine.function, map.function ]
|
functions = [ map.function ]
|
||||||
methods = [ get.function ]
|
methods = [ get.function ]
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
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')
|
|
||||||
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
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([ Type.integer(i) for i in range(upper.value + 1)])
|
|
||||||
|
|
||||||
|
|
||||||
_signature2 = signature(ofType(Type.INTEGER), ofType(Type.INTEGER))
|
|
||||||
def _function2(env, lower, upper):
|
|
||||||
return Type.list([ Type.integer(i) for i in 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([ Type.integer(i) for i in 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.string.function import concat, stringify
|
from smnp.module.string.function import stringify
|
||||||
|
|
||||||
functions = [ concat.function ]
|
functions = []
|
||||||
methods = [ stringify.function ]
|
methods = [ stringify.function ]
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
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,4 +1,4 @@
|
|||||||
from smnp.module.system.function import sleep, display, displayln, debug, exit, type
|
from smnp.module.system.function import sleep, display, displayln, debug, exit, type, read
|
||||||
|
|
||||||
functions = [ debug.function, display.function, displayln.function, exit.function, sleep.function, type.function ]
|
functions = [ debug.function, display.function, displayln.function, exit.function, sleep.function, type.function, read.function ]
|
||||||
methods = []
|
methods = []
|
||||||
@@ -1,3 +1,72 @@
|
|||||||
|
from smnp.error.runtime import RuntimeException
|
||||||
|
from smnp.function.model import CombinedFunction, Function
|
||||||
|
from smnp.function.signature import signature
|
||||||
|
from smnp.token.tokenizers.bool import boolTokenizer
|
||||||
|
from smnp.token.tokenizers.note import noteTokenizer
|
||||||
|
from smnp.type.model import Type
|
||||||
|
from smnp.type.signature.matcher.type import ofType
|
||||||
|
|
||||||
|
_signature1 = signature()
|
||||||
|
def _function1(env):
|
||||||
|
value = input()
|
||||||
|
return Type.string(value)
|
||||||
|
|
||||||
|
|
||||||
|
_signature2 = signature(ofType(Type.STRING))
|
||||||
|
def _function2(env, prompt):
|
||||||
|
print(prompt.value, end="")
|
||||||
|
value = input()
|
||||||
|
return Type.string(value)
|
||||||
|
|
||||||
|
|
||||||
|
_signature3 = signature(ofType(Type.TYPE))
|
||||||
|
def _function3(env, type):
|
||||||
|
value = input()
|
||||||
|
return getValueAccordingToType(value, type)
|
||||||
|
|
||||||
|
|
||||||
|
def getValueAccordingToType(value, type):
|
||||||
|
try:
|
||||||
|
if type.value == Type.STRING:
|
||||||
|
return Type.string(value)
|
||||||
|
|
||||||
|
if type.value == Type.INTEGER:
|
||||||
|
return Type.integer(int(value))
|
||||||
|
|
||||||
|
if type.value == Type.BOOL:
|
||||||
|
consumedChars, token = boolTokenizer(value, 0, 0)
|
||||||
|
if consumedChars > 0:
|
||||||
|
return Type.bool(token.value)
|
||||||
|
|
||||||
|
return ValueError()
|
||||||
|
|
||||||
|
if type.value == Type.NOTE:
|
||||||
|
consumedChars, token = noteTokenizer(value, 0, 0)
|
||||||
|
if consumedChars > 0:
|
||||||
|
return Type.note(token.value)
|
||||||
|
|
||||||
|
raise ValueError()
|
||||||
|
|
||||||
|
raise RuntimeException(f"Type {type.value.name.lower()} is not suuported", None)
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
raise RuntimeException(f"Invalid value '{value}' for type {type.value.name.lower()}", None)
|
||||||
|
|
||||||
|
|
||||||
|
_signature4 = signature(ofType(Type.STRING), ofType(Type.TYPE))
|
||||||
|
def _function4(env, prompt, type):
|
||||||
|
print(prompt.value, end="")
|
||||||
|
value = input()
|
||||||
|
return getValueAccordingToType(value, type)
|
||||||
|
|
||||||
|
|
||||||
|
function = CombinedFunction(
|
||||||
|
'read',
|
||||||
|
Function(_signature1, _function1),
|
||||||
|
Function(_signature2, _function2),
|
||||||
|
Function(_signature3, _function3),
|
||||||
|
Function(_signature4, _function4)
|
||||||
|
)
|
||||||
|
|
||||||
# TODO read function
|
# TODO read function
|
||||||
# def read(args, env):
|
# def read(args, env):
|
||||||
|
|||||||
@@ -8,11 +8,7 @@ class AssignmentEvaluator(Evaluator):
|
|||||||
def evaluator(cls, node, environment):
|
def evaluator(cls, node, environment):
|
||||||
target = node.left.value
|
target = node.left.value
|
||||||
value = expressionEvaluator(doAssert=True)(node.right, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
|
value = expressionEvaluator(doAssert=True)(node.right, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
|
||||||
scopeOfExistingVariable = environment.findVariableScope(target)
|
environment.scopes[-1][target] = value
|
||||||
if scopeOfExistingVariable is None:
|
|
||||||
environment.scopes[-1][target] = value
|
|
||||||
else:
|
|
||||||
scopeOfExistingVariable[target] = value
|
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
from smnp.ast.node.identifier import Identifier
|
|
||||||
from smnp.runtime.evaluator import evaluate, Evaluator, EvaluationResult
|
|
||||||
from smnp.runtime.evaluators.expression import expressionEvaluator
|
|
||||||
from smnp.type.model import Type
|
|
||||||
|
|
||||||
|
|
||||||
class AsteriskEvaluator(Evaluator):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def evaluator(cls, node, environment):
|
|
||||||
iterator = expressionEvaluator(doAssert=True)(node.iterator, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
|
|
||||||
return Evaluator.oneOf(
|
|
||||||
cls._numberIteratorAsteriskEvaluator(iterator),
|
|
||||||
cls._listIteratorAsteriskEvaluator(iterator),
|
|
||||||
cls._mapIteratorAsteriskEvaluator(iterator)
|
|
||||||
)(node, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _numberIteratorAsteriskEvaluator(cls, evaluatedIterator):
|
|
||||||
def evaluator(node, environment):
|
|
||||||
if evaluatedIterator.type == Type.INTEGER:
|
|
||||||
results = []
|
|
||||||
automaticVariable = cls._automaticNamedVariable(node.iterator, environment, "_")
|
|
||||||
for i in range(evaluatedIterator.value):
|
|
||||||
environment.scopes[-1][automaticVariable] = Type.integer(i + 1)
|
|
||||||
result = evaluate(node.statement, environment).value #TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
|
|
||||||
if result is None or result.type == Type.VOID:
|
|
||||||
results = None
|
|
||||||
|
|
||||||
if results is not None:
|
|
||||||
results.append(result)
|
|
||||||
|
|
||||||
del environment.scopes[-1][automaticVariable]
|
|
||||||
|
|
||||||
return EvaluationResult.OK(Type.list(results).decompose() if results is not None else Type.void())
|
|
||||||
|
|
||||||
return EvaluationResult.FAIL()
|
|
||||||
|
|
||||||
return evaluator
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _automaticNamedVariable(cls, iteratorNode, environment, prefix=''):
|
|
||||||
if type(iteratorNode) == Identifier:
|
|
||||||
return cls._automaticVariableName(environment, prefix, iteratorNode.value, False)
|
|
||||||
else:
|
|
||||||
return cls._automaticVariableName(environment, prefix, '', True)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _automaticVariableName(cls, environment, prefix='', suffix='', startWithNumber=False):
|
|
||||||
number = 1 if startWithNumber else ''
|
|
||||||
variableName = lambda x: f"{prefix}{x}{suffix}"
|
|
||||||
while environment.findVariableScope(variableName(number)) is not None:
|
|
||||||
if number == '':
|
|
||||||
number = 1
|
|
||||||
else:
|
|
||||||
number += 1
|
|
||||||
|
|
||||||
return variableName(number)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _listIteratorAsteriskEvaluator(cls, evaluatedIterator):
|
|
||||||
def evaluator(node, environment):
|
|
||||||
if evaluatedIterator.type == Type.LIST:
|
|
||||||
results = []
|
|
||||||
automaticVariableKey = cls._automaticNamedVariable(node.iterator, environment, "_")
|
|
||||||
automaticVariableValue = cls._automaticNamedVariable(node.iterator, environment, "__")
|
|
||||||
for i, v in enumerate(evaluatedIterator.value):
|
|
||||||
environment.scopes[-1][automaticVariableKey] = Type.integer(i + 1)
|
|
||||||
environment.scopes[-1][automaticVariableValue] = v
|
|
||||||
result = evaluate(node.statement, environment).value # TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
|
|
||||||
if result is not None and result.type != Type.VOID:
|
|
||||||
results.append(result)
|
|
||||||
|
|
||||||
del environment.scopes[-1][automaticVariableKey]
|
|
||||||
del environment.scopes[-1][automaticVariableValue]
|
|
||||||
|
|
||||||
return EvaluationResult.OK(Type.list(results).decompose())
|
|
||||||
|
|
||||||
return EvaluationResult.FAIL()
|
|
||||||
|
|
||||||
return evaluator
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _mapIteratorAsteriskEvaluator(cls, evaluatedIterator):
|
|
||||||
def evaluator(node, environment):
|
|
||||||
if evaluatedIterator.type == Type.MAP:
|
|
||||||
results = []
|
|
||||||
automaticVariableKey = cls._automaticNamedVariable(node.iterator, environment, "_")
|
|
||||||
automaticVariableValue = cls._automaticNamedVariable(node.iterator, environment, "__")
|
|
||||||
for k, v in evaluatedIterator.value.items():
|
|
||||||
environment.scopes[-1][automaticVariableKey] = k
|
|
||||||
environment.scopes[-1][automaticVariableValue] = v
|
|
||||||
result = evaluate(node.statement, environment).value # TODO check if it isn't necessary to verify 'result' attr of EvaluatioNResult
|
|
||||||
if result is not None and result.type != Type.VOID:
|
|
||||||
results.append(result)
|
|
||||||
|
|
||||||
del environment.scopes[-1][automaticVariableKey]
|
|
||||||
del environment.scopes[-1][automaticVariableValue]
|
|
||||||
|
|
||||||
return EvaluationResult.OK(Type.list(results).decompose())
|
|
||||||
|
|
||||||
return EvaluationResult.FAIL()
|
|
||||||
|
|
||||||
return evaluator
|
|
||||||
@@ -5,12 +5,12 @@ class BlockEvaluator(Evaluator):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def evaluator(cls, node, environment):
|
def evaluator(cls, node, environment):
|
||||||
environment.scopes.append({})
|
environment.appendScope()
|
||||||
|
|
||||||
for child in node.children:
|
for child in node.children:
|
||||||
evaluate(child, environment)
|
evaluate(child, environment)
|
||||||
|
|
||||||
environment.scopes.pop(-1)
|
environment.popScope()
|
||||||
|
|
||||||
#
|
#
|
||||||
# def evaluateBlock(block, environment):
|
# def evaluateBlock(block, environment):
|
||||||
|
|||||||
@@ -13,23 +13,23 @@ class LoopEvaluator(Evaluator):
|
|||||||
parameters = [ identifier.value for identifier in node.parameters ] if type(node.parameters) != NoneNode() else []
|
parameters = [ identifier.value for identifier in node.parameters ] if type(node.parameters) != NoneNode() else []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
environment.scopes.append({})
|
environment.appendScope()
|
||||||
|
|
||||||
output = {
|
output = {
|
||||||
Type.INTEGER: cls.numberEvaluator,
|
Type.INTEGER: cls.numberEvaluator,
|
||||||
Type.BOOL: cls.boolEvaluator,
|
Type.BOOL: cls.boolEvaluator,
|
||||||
Type.LIST: cls.listEvaluator,
|
Type.LIST: cls.listEvaluator,
|
||||||
Type.MAP: cls.mapEvaluator
|
Type.MAP: cls.mapEvaluator
|
||||||
}[iterator.type](node, environment, iterator, parameters)
|
}[iterator.type](node, environment, iterator, parameters, node.filter)
|
||||||
|
|
||||||
environment.scopes.pop(-1)
|
environment.popScope()
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise RuntimeException(f"The {iterator.type.name.lower()} type cannot stand as an iterator for loop statement", node.left.pos)
|
raise RuntimeException(f"The {iterator.type.name.lower()} type cannot stand as an iterator for loop statement", node.left.pos)
|
||||||
|
|
||||||
return Type.list(output)
|
return Type.list(output)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def numberEvaluator(cls, node, environment, evaluatedIterator, parameters):
|
def numberEvaluator(cls, node, environment, evaluatedIterator, parameters, filter):
|
||||||
output = []
|
output = []
|
||||||
|
|
||||||
|
|
||||||
@@ -40,14 +40,28 @@ class LoopEvaluator(Evaluator):
|
|||||||
if len(parameters) > 0:
|
if len(parameters) > 0:
|
||||||
environment.scopes[-1][parameters[0]] = Type.integer(i)
|
environment.scopes[-1][parameters[0]] = Type.integer(i)
|
||||||
|
|
||||||
output.append(evaluate(node.right, environment).value)
|
if cls.doFilter(filter, environment):
|
||||||
|
output.append(evaluate(node.right, environment).value)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def boolEvaluator(cls, node, environment, evaluatedIterator, parameters):
|
def doFilter(cls, filter, environment):
|
||||||
|
if type(filter) is not NoneNode:
|
||||||
|
evaluation = expressionEvaluator(doAssert=True)(filter, environment).value
|
||||||
|
if evaluation.type != Type.BOOL:
|
||||||
|
raise RuntimeException(f"Expected {Type.BOOL.name.lower()} as filter expression, found {evaluation.type.name.lower()}", filter.pos)
|
||||||
|
|
||||||
|
return evaluation.value
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def boolEvaluator(cls, node, environment, evaluatedIterator, parameters, filter):
|
||||||
output = []
|
output = []
|
||||||
|
|
||||||
if len(parameters) > 0:
|
if len(parameters) > 0:
|
||||||
@@ -55,13 +69,14 @@ class LoopEvaluator(Evaluator):
|
|||||||
|
|
||||||
condition = evaluatedIterator
|
condition = evaluatedIterator
|
||||||
while condition.value:
|
while condition.value:
|
||||||
output.append(evaluate(node.right, environment).value)
|
if cls.doFilter(filter, environment):
|
||||||
|
output.append(evaluate(node.right, environment).value)
|
||||||
condition = expressionEvaluator(doAssert=True)(node.left, environment).value
|
condition = expressionEvaluator(doAssert=True)(node.left, environment).value
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def listEvaluator(cls, node, environment, evaluatedIterator, parameters):
|
def listEvaluator(cls, node, environment, evaluatedIterator, parameters, filter):
|
||||||
output = []
|
output = []
|
||||||
|
|
||||||
if len(parameters) > 2:
|
if len(parameters) > 2:
|
||||||
@@ -74,13 +89,14 @@ class LoopEvaluator(Evaluator):
|
|||||||
environment.scopes[-1][parameters[0]] = Type.integer(i)
|
environment.scopes[-1][parameters[0]] = Type.integer(i)
|
||||||
environment.scopes[-1][parameters[1]] = value
|
environment.scopes[-1][parameters[1]] = value
|
||||||
|
|
||||||
output.append(evaluate(node.right, environment).value)
|
if cls.doFilter(filter, environment):
|
||||||
|
output.append(evaluate(node.right, environment).value)
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def mapEvaluator(cls, node, environment, evaluatedIterator, parameters):
|
def mapEvaluator(cls, node, environment, evaluatedIterator, parameters, filter):
|
||||||
output = []
|
output = []
|
||||||
|
|
||||||
if len(parameters) > 3:
|
if len(parameters) > 3:
|
||||||
@@ -99,6 +115,7 @@ class LoopEvaluator(Evaluator):
|
|||||||
environment.scopes[-1][parameters[2]] = value
|
environment.scopes[-1][parameters[2]] = value
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
output.append(evaluate(node.right, environment).value)
|
if cls.doFilter(filter, environment):
|
||||||
|
output.append(evaluate(node.right, environment).value)
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ tokenizers = (
|
|||||||
defaultTokenizer(TokenType.CLOSE_ANGLE),
|
defaultTokenizer(TokenType.CLOSE_ANGLE),
|
||||||
defaultTokenizer(TokenType.SEMICOLON),
|
defaultTokenizer(TokenType.SEMICOLON),
|
||||||
defaultTokenizer(TokenType.ASTERISK),
|
defaultTokenizer(TokenType.ASTERISK),
|
||||||
|
defaultTokenizer(TokenType.PERCENT),
|
||||||
defaultTokenizer(TokenType.ASSIGN),
|
defaultTokenizer(TokenType.ASSIGN),
|
||||||
defaultTokenizer(TokenType.COMMA),
|
defaultTokenizer(TokenType.COMMA),
|
||||||
defaultTokenizer(TokenType.SLASH),
|
defaultTokenizer(TokenType.SLASH),
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class TokenType(Enum):
|
|||||||
CLOSE_ANGLE = '>'
|
CLOSE_ANGLE = '>'
|
||||||
SEMICOLON = ';'
|
SEMICOLON = ';'
|
||||||
ASTERISK = '*'
|
ASTERISK = '*'
|
||||||
|
PERCENT = '%'
|
||||||
ASSIGN = '='
|
ASSIGN = '='
|
||||||
ARROW = '->'
|
ARROW = '->'
|
||||||
COMMA = ','
|
COMMA = ','
|
||||||
@@ -44,7 +45,6 @@ class TokenType(Enum):
|
|||||||
AS = 'as'
|
AS = 'as'
|
||||||
IDENTIFIER = 'identifier'
|
IDENTIFIER = 'identifier'
|
||||||
COMMENT = 'comment'
|
COMMENT = 'comment'
|
||||||
PERCENT = 'percent'
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def key(self):
|
def key(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user