aboutsummaryrefslogtreecommitdiff
path: root/ql/ast/visitors
diff options
context:
space:
mode:
Diffstat (limited to 'ql/ast/visitors')
-rw-r--r--ql/ast/visitors/__pycache__/dependency_visitor.cpython-35.pycbin0 -> 2626 bytes
-rw-r--r--ql/ast/visitors/__pycache__/expression_evaluator.cpython-35.pycbin0 -> 1834 bytes
-rw-r--r--ql/ast/visitors/__pycache__/identifier_type_visitor.cpython-35.pycbin0 -> 1552 bytes
-rw-r--r--ql/ast/visitors/__pycache__/model_generator.cpython-35.pycbin0 -> 1918 bytes
-rw-r--r--ql/ast/visitors/__pycache__/question_visitor.cpython-35.pycbin0 -> 1555 bytes
-rw-r--r--ql/ast/visitors/__pycache__/reference_visitor.cpython-35.pycbin0 -> 2997 bytes
-rw-r--r--ql/ast/visitors/__pycache__/type_visitor.cpython-35.pycbin0 -> 3387 bytes
-rw-r--r--ql/ast/visitors/dependency_visitor.py54
-rw-r--r--ql/ast/visitors/expression_evaluator.py37
-rw-r--r--ql/ast/visitors/identifier_type_visitor.py31
-rw-r--r--ql/ast/visitors/model_generator.py39
-rw-r--r--ql/ast/visitors/question_visitor.py33
-rw-r--r--ql/ast/visitors/reference_visitor.py86
-rw-r--r--ql/ast/visitors/type_visitor.py85
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
new file mode 100644
index 0000000..8d348e6
--- /dev/null
+++ b/ql/ast/visitors/__pycache__/dependency_visitor.cpython-35.pyc
Binary files differ
diff --git a/ql/ast/visitors/__pycache__/expression_evaluator.cpython-35.pyc b/ql/ast/visitors/__pycache__/expression_evaluator.cpython-35.pyc
new file mode 100644
index 0000000..29a2e9b
--- /dev/null
+++ b/ql/ast/visitors/__pycache__/expression_evaluator.cpython-35.pyc
Binary files differ
diff --git a/ql/ast/visitors/__pycache__/identifier_type_visitor.cpython-35.pyc b/ql/ast/visitors/__pycache__/identifier_type_visitor.cpython-35.pyc
new file mode 100644
index 0000000..89f690d
--- /dev/null
+++ b/ql/ast/visitors/__pycache__/identifier_type_visitor.cpython-35.pyc
Binary files differ
diff --git a/ql/ast/visitors/__pycache__/model_generator.cpython-35.pyc b/ql/ast/visitors/__pycache__/model_generator.cpython-35.pyc
new file mode 100644
index 0000000..9950522
--- /dev/null
+++ b/ql/ast/visitors/__pycache__/model_generator.cpython-35.pyc
Binary files differ
diff --git a/ql/ast/visitors/__pycache__/question_visitor.cpython-35.pyc b/ql/ast/visitors/__pycache__/question_visitor.cpython-35.pyc
new file mode 100644
index 0000000..ac60a13
--- /dev/null
+++ b/ql/ast/visitors/__pycache__/question_visitor.cpython-35.pyc
Binary files differ
diff --git a/ql/ast/visitors/__pycache__/reference_visitor.cpython-35.pyc b/ql/ast/visitors/__pycache__/reference_visitor.cpython-35.pyc
new file mode 100644
index 0000000..e0491b9
--- /dev/null
+++ b/ql/ast/visitors/__pycache__/reference_visitor.cpython-35.pyc
Binary files differ
diff --git a/ql/ast/visitors/__pycache__/type_visitor.cpython-35.pyc b/ql/ast/visitors/__pycache__/type_visitor.cpython-35.pyc
new file mode 100644
index 0000000..a2df3f2
--- /dev/null
+++ b/ql/ast/visitors/__pycache__/type_visitor.cpython-35.pyc
Binary files differ
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