diff options
Diffstat (limited to 'ql/ast/visitors')
| -rw-r--r-- | ql/ast/visitors/__pycache__/dependency_visitor.cpython-35.pyc | bin | 0 -> 2626 bytes | |||
| -rw-r--r-- | ql/ast/visitors/__pycache__/expression_evaluator.cpython-35.pyc | bin | 0 -> 1834 bytes | |||
| -rw-r--r-- | ql/ast/visitors/__pycache__/identifier_type_visitor.cpython-35.pyc | bin | 0 -> 1552 bytes | |||
| -rw-r--r-- | ql/ast/visitors/__pycache__/model_generator.cpython-35.pyc | bin | 0 -> 1918 bytes | |||
| -rw-r--r-- | ql/ast/visitors/__pycache__/question_visitor.cpython-35.pyc | bin | 0 -> 1555 bytes | |||
| -rw-r--r-- | ql/ast/visitors/__pycache__/reference_visitor.cpython-35.pyc | bin | 0 -> 2997 bytes | |||
| -rw-r--r-- | ql/ast/visitors/__pycache__/type_visitor.cpython-35.pyc | bin | 0 -> 3387 bytes | |||
| -rw-r--r-- | ql/ast/visitors/dependency_visitor.py | 54 | ||||
| -rw-r--r-- | ql/ast/visitors/expression_evaluator.py | 37 | ||||
| -rw-r--r-- | ql/ast/visitors/identifier_type_visitor.py | 31 | ||||
| -rw-r--r-- | ql/ast/visitors/model_generator.py | 39 | ||||
| -rw-r--r-- | ql/ast/visitors/question_visitor.py | 33 | ||||
| -rw-r--r-- | ql/ast/visitors/reference_visitor.py | 86 | ||||
| -rw-r--r-- | ql/ast/visitors/type_visitor.py | 85 |
14 files changed, 365 insertions, 0 deletions
diff --git a/ql/ast/visitors/__pycache__/dependency_visitor.cpython-35.pyc b/ql/ast/visitors/__pycache__/dependency_visitor.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..8d348e6 --- /dev/null +++ b/ql/ast/visitors/__pycache__/dependency_visitor.cpython-35.pyc diff --git a/ql/ast/visitors/__pycache__/expression_evaluator.cpython-35.pyc b/ql/ast/visitors/__pycache__/expression_evaluator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..29a2e9b --- /dev/null +++ b/ql/ast/visitors/__pycache__/expression_evaluator.cpython-35.pyc diff --git a/ql/ast/visitors/__pycache__/identifier_type_visitor.cpython-35.pyc b/ql/ast/visitors/__pycache__/identifier_type_visitor.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..89f690d --- /dev/null +++ b/ql/ast/visitors/__pycache__/identifier_type_visitor.cpython-35.pyc diff --git a/ql/ast/visitors/__pycache__/model_generator.cpython-35.pyc b/ql/ast/visitors/__pycache__/model_generator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..9950522 --- /dev/null +++ b/ql/ast/visitors/__pycache__/model_generator.cpython-35.pyc diff --git a/ql/ast/visitors/__pycache__/question_visitor.cpython-35.pyc b/ql/ast/visitors/__pycache__/question_visitor.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..ac60a13 --- /dev/null +++ b/ql/ast/visitors/__pycache__/question_visitor.cpython-35.pyc diff --git a/ql/ast/visitors/__pycache__/reference_visitor.cpython-35.pyc b/ql/ast/visitors/__pycache__/reference_visitor.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..e0491b9 --- /dev/null +++ b/ql/ast/visitors/__pycache__/reference_visitor.cpython-35.pyc diff --git a/ql/ast/visitors/__pycache__/type_visitor.cpython-35.pyc b/ql/ast/visitors/__pycache__/type_visitor.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..a2df3f2 --- /dev/null +++ b/ql/ast/visitors/__pycache__/type_visitor.cpython-35.pyc diff --git a/ql/ast/visitors/dependency_visitor.py b/ql/ast/visitors/dependency_visitor.py new file mode 100644 index 0000000..8bb81eb --- /dev/null +++ b/ql/ast/visitors/dependency_visitor.py @@ -0,0 +1,54 @@ +from multimethods import multimethod + +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.ast.nodes.expressions.literals.literal import LiteralNode +from ql.ast.nodes.expressions.unary_operators.unary_operator import UnaryOperatorNode +from ql.ast.nodes.expressions.variable import VariableNode +from ql.ast.nodes.statements.form_statement import FormNode +from ql.ast.nodes.statements.if_statement import IfNode +from ql.ast.nodes.statements.question_statement import QuestionNode + + +class DependencyVisitor: + def __init__(self): + self.__all_dependencies = [] + self.__current_dependencies = [] + + @property + def identifier_dependencies(self): + return self.__all_dependencies + + @multimethod(FormNode) + def visit(self, node): + for child in node.block: + child.accept(self) + + @multimethod(IfNode) + def visit(self, node): + node.condition.accept(self) + for child in node.block: + child.accept(self) + + @multimethod(QuestionNode) + def visit(self, node): + if node.computed: + self.__current_dependencies = [] + node.answer.accept(self) + self.__all_dependencies.append((node.identifier, self.__current_dependencies, node.metadata)) + + @multimethod(BinaryOperatorNode) + def visit(self, node): + node.left_expression.accept(self) + node.right_expression.accept(self) + + @multimethod(UnaryOperatorNode) + def visit(self, node): + node.expression.accept(self) + + @multimethod(VariableNode) + def visit(self, node): + self.__current_dependencies.append(node.identifier) + + @multimethod(LiteralNode) + def visit(self, node): + pass diff --git a/ql/ast/visitors/expression_evaluator.py b/ql/ast/visitors/expression_evaluator.py new file mode 100644 index 0000000..9306d98 --- /dev/null +++ b/ql/ast/visitors/expression_evaluator.py @@ -0,0 +1,37 @@ +from multimethods import multimethod + +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.ast.nodes.expressions.literals.literal import LiteralNode +from ql.ast.nodes.expressions.unary_operators.unary_operator import UnaryOperatorNode +from ql.ast.nodes.expressions.variable import VariableNode +from ql.types.undefined import QLUndefined + + +class ExpressionEvaluator: + def __init__(self, form): + self.form = form + self.result = QLUndefined() + + @multimethod(BinaryOperatorNode) + def visit(self, node): + node.left_expression.accept(self) + node.right_expression.accept(self) + node.evaluate() + self.result = node.value + + @multimethod(UnaryOperatorNode) + def visit(self, node): + node.expression.accept(self) + node.evaluate() + self.result = node.value + + @multimethod(LiteralNode) + def visit(self, node): + self.result = node.value + + @multimethod(VariableNode) + def visit(self, node): + for question in self.form.block: + if node.identifier == question.identifier: + node.value = question.answer.value + self.result = node.value diff --git a/ql/ast/visitors/identifier_type_visitor.py b/ql/ast/visitors/identifier_type_visitor.py new file mode 100644 index 0000000..d064f5b --- /dev/null +++ b/ql/ast/visitors/identifier_type_visitor.py @@ -0,0 +1,31 @@ +from multimethods import multimethod + +from ql.ast.nodes.statements.form_statement import FormNode +from ql.ast.nodes.statements.if_statement import IfNode +from ql.ast.nodes.statements.question_statement import QuestionNode + + +class IdentifierTypeVisitor: + def __init__(self): + self.__symbol_table = [] + + @property + def symbol_table(self): + return self.__symbol_table + + @multimethod(FormNode) + def visit(self, node): + for child in node.block: + child.accept(self) + + @multimethod(IfNode) + def visit(self, node): + for child in node.block: + child.accept(self) + + @multimethod(QuestionNode) + def visit(self, node): + self.__symbol_table.append({ + 'identifier': node.identifier, + 'answer_type': node.answer_type, + }) diff --git a/ql/ast/visitors/model_generator.py b/ql/ast/visitors/model_generator.py new file mode 100644 index 0000000..f2cf5d8 --- /dev/null +++ b/ql/ast/visitors/model_generator.py @@ -0,0 +1,39 @@ +from multimethods import multimethod + +from gui.model.form import FormModel +from gui.model.question import QuestionModel +from ql.ast.nodes.expressions.binary_operators.and_operator import AndOperatorNode +from ql.ast.nodes.statements.form_statement import FormNode +from ql.ast.nodes.statements.if_statement import IfNode +from ql.ast.nodes.statements.question_statement import QuestionNode +from ql.types.boolean import QLBoolean +from ql.types.undefined import QLUndefined + + +class ModelGenerator: + def __init__(self): + self.form = None + self.condition = QLBoolean.get_literal_node(True) + + @multimethod(FormNode) + def visit(self, node): + self.form = FormModel(node.identifier) + + for child in node.block: + child.accept(self) + + @multimethod(IfNode) + def visit(self, node): + previous_condition = self.condition + self.condition = AndOperatorNode(None, QLBoolean, self.condition, node.condition, QLUndefined()) + + for child in node.block: + child.accept(self) + + self.condition = previous_condition + + @multimethod(QuestionNode) + def visit(self, node): + question_model = QuestionModel(node.label, node.identifier, node.answer_type, + node.answer, node.computed, self.condition) + self.form.block.append(question_model) diff --git a/ql/ast/visitors/question_visitor.py b/ql/ast/visitors/question_visitor.py new file mode 100644 index 0000000..8037364 --- /dev/null +++ b/ql/ast/visitors/question_visitor.py @@ -0,0 +1,33 @@ +from multimethods import multimethod + +from ql.ast.nodes.statements.form_statement import FormNode +from ql.ast.nodes.statements.if_statement import IfNode +from ql.ast.nodes.statements.question_statement import QuestionNode + + +class QuestionVisitor: + def __init__(self): + self.__questions = [] + + @property + def questions(self): + return self.__questions + + @multimethod(FormNode) + def visit(self, node): + for child in node.block: + child.accept(self) + + @multimethod(IfNode) + def visit(self, node): + for child in node.block: + child.accept(self) + + @multimethod(QuestionNode) + def visit(self, node): + self.__questions.append({ + 'label': node.label, + 'identifier': node.identifier, + 'answer_type': node.answer_type, + 'metadata': node.metadata, + }) diff --git a/ql/ast/visitors/reference_visitor.py b/ql/ast/visitors/reference_visitor.py new file mode 100644 index 0000000..5cbbcc7 --- /dev/null +++ b/ql/ast/visitors/reference_visitor.py @@ -0,0 +1,86 @@ +from multimethods import multimethod + +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.ast.nodes.expressions.literals.literal import LiteralNode +from ql.ast.nodes.expressions.unary_operators.unary_operator import UnaryOperatorNode +from ql.ast.nodes.expressions.variable import VariableNode +from ql.ast.nodes.statements.form_statement import FormNode +from ql.ast.nodes.statements.if_statement import IfNode +from ql.ast.nodes.statements.question_statement import QuestionNode + + +class ReferenceVisitor: + def __init__(self): + self.__current_block = [] + self.__current_scope = {} + + @property + def identifier_scopes(self): + return self.__current_scope + + @multimethod(FormNode) + def visit(self, node): + self.__current_scope = { + 'content': [], + 'children': [], + } + self.__current_block = [] + + for child in node.block: + child.accept(self) + + self.__current_scope['content'] = self.__current_block + + @multimethod(IfNode) + def visit(self, node): + node.condition.accept(self) + + self.__current_scope['content'] += self.__current_block + previous_scope = self.__current_scope + previous_block = self.__current_block + self.__current_block = [] + self.__current_scope = { + 'content': [], + 'children': [], + } + + for child in node.block: + child.accept(self) + + self.__current_scope['content'] = self.__current_block + previous_scope['children'].append(self.__current_scope) + self.__current_block = previous_block + self.__current_scope = previous_scope + + @multimethod(QuestionNode) + def visit(self, node): + self.__current_block.append(dict({ + 'name': node.identifier, + 'type': node.answer_type, + 'line': node.metadata.line, + })) + + if node.computed: + node.answer.accept(self) + + @multimethod(BinaryOperatorNode) + def visit(self, node): + node.left_expression.accept(self) + node.right_expression.accept(self) + + @multimethod(UnaryOperatorNode) + def visit(self, node): + node.expression.accept(self) + + @multimethod(VariableNode) + def visit(self, node): + name = node.identifier + self.__current_block.append({ + 'name': name, + 'type': [], + 'line': node.metadata.line, + }) + + @multimethod(LiteralNode) + def visit(self, node): + pass diff --git a/ql/ast/visitors/type_visitor.py b/ql/ast/visitors/type_visitor.py new file mode 100644 index 0000000..7f4ac7c --- /dev/null +++ b/ql/ast/visitors/type_visitor.py @@ -0,0 +1,85 @@ +from multimethods import multimethod + +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.ast.nodes.expressions.literals.literal import LiteralNode +from ql.ast.nodes.expressions.unary_operators.unary_operator import UnaryOperatorNode +from ql.ast.nodes.expressions.variable import VariableNode +from ql.ast.nodes.statements.form_statement import FormNode +from ql.ast.nodes.statements.if_statement import IfNode +from ql.ast.nodes.statements.question_statement import QuestionNode +from ql.types.boolean import QLBoolean +from ql.types.undefined import QLUndefined + + +class TypeVisitor: + def __init__(self, symbol_table): + self.__symbol_table = symbol_table + self.__errors = [] + + @property + def errors(self): + return self.__errors + + @multimethod(FormNode) + def visit(self, node): + for child in node.block: + child.accept(self) + + @multimethod(IfNode) + def visit(self, node): + node.condition.accept(self) + + if node.condition.expression_type != QLBoolean: + self.__errors.append('Condition does not evaluate to boolean on line {}.' + .format(node.metadata.line)) + + for child in node.block: + child.accept(self) + + @multimethod(QuestionNode) + def visit(self, node): + if node.computed: + node.answer.accept(self) + + result_type = node.answer.expression_type + + if node.answer_type != result_type: + self.__errors.append('Expression not of type {} on line {}' + .format(node.answer_type, node.answer.metadata.line)) + + @multimethod(BinaryOperatorNode) + def visit(self, node): + node.left_expression.accept(self) + node.right_expression.accept(self) + + result_type = node.get_result_type() + + if result_type == QLUndefined: + self.__errors.append('Invalid operands: {} and {} not supported for binary operation on line {}' + .format(node.left_expression.expression_type, + node.right_expression.expression_type, + node.metadata.line)) + + node.expression_type = result_type + + @multimethod(UnaryOperatorNode) + def visit(self, node): + node.expression.accept(self) + + result_type = node.get_result_type() + + if result_type == QLUndefined: + self.__errors.append('Invalid operand: {} not supported for unary operation on line {}' + .format(node.expression.expression_type, node.metadata.line)) + + node.expression_type = result_type + + @multimethod(VariableNode) + def visit(self, node): + for row in self.__symbol_table: + if row['identifier'] == node.identifier: + node.expression_type = row['answer_type'] + + @multimethod(LiteralNode) + def visit(self, node): + pass |