diff options
| author | Bicker <bickerkards@tuta.io> | 2019-05-22 17:45:37 +0200 |
|---|---|---|
| committer | Bicker <bickerkards@tuta.io> | 2019-05-22 17:45:37 +0200 |
| commit | 25314fd2aed81aa5281bc3d93dbcc7919368ebe1 (patch) | |
| tree | 1995521ee652e419926de5fced0f2e3b655e70fb | |
305 files changed, 6007 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..7a7b6b3 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# PyQuest
+---
+> Repository for the course *Software Construction*, part of the master *Software Engineering* at the *University of Amsterdam*
+---
+
+This repository contains code implementing a Questionnaire Language (QL) in Python.
+
+## Dependencies
+### Python
+Python version 3
+
+#### Packages
+- multimethods
+- PLY
+- PyQt5
+- termcolor
+## Setup
+```
+sudo pip3 install multimethods
+sudo pip3 install ply
+sudo pip3 install pyqt5
+sudo pip3 install termcolor
+```
+
+
+## Running
+```
+python3 pyquest.py
+```
+
+### Optional arguments
+```
+-t, --test Perform tests.
+```
+
+### GUI Shortcuts
+
+| Shortcut | Action |
+| ------ | ------ |
+| `Ctrl+N`| Create a new .ql file |
+| `Ctrl+O`| Open a .ql file |
+| `Ctrl+S`| Save current .ql file |
+| `Ctrl+Shift+S`| Save as current .ql file |
+| `Ctrl+R` | Run current .ql file |
+
diff --git a/gui/__pycache__/helper.cpython-35.pyc b/gui/__pycache__/helper.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..ee2c6ac --- /dev/null +++ b/gui/__pycache__/helper.cpython-35.pyc diff --git a/gui/helper.py b/gui/helper.py new file mode 100644 index 0000000..615c87a --- /dev/null +++ b/gui/helper.py @@ -0,0 +1,23 @@ +from PyQt5.QtWidgets import QMessageBox + + +def append_file_extension(file_name, extension): + if not file_name.endswith('.' + extension): + return '{}.{}'.format(file_name, extension) + return file_name + + +def error(errors): + message = '\n'.join(errors) + QMessageBox.critical(QMessageBox(), 'Error', message, QMessageBox.Close, QMessageBox.Escape) + + +def warning(warnings): + message = '\n'.join(warnings) + QMessageBox.warning(QMessageBox(), 'Warning', message, QMessageBox.Close, QMessageBox.Escape) + + +def check_errors(errors): + if errors: + error(errors) + raise SyntaxError diff --git a/gui/model/__pycache__/form.cpython-35.pyc b/gui/model/__pycache__/form.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..cd48947 --- /dev/null +++ b/gui/model/__pycache__/form.cpython-35.pyc diff --git a/gui/model/__pycache__/question.cpython-35.pyc b/gui/model/__pycache__/question.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..64bb4cf --- /dev/null +++ b/gui/model/__pycache__/question.cpython-35.pyc diff --git a/gui/model/form.py b/gui/model/form.py new file mode 100644 index 0000000..3f045ce --- /dev/null +++ b/gui/model/form.py @@ -0,0 +1,44 @@ +from json import dumps + + +class FormModel: + def __init__(self, identifier): + self.__identifier = identifier + self.__block = [] + + @property + def identifier(self): + return self.__identifier + + @property + def block(self): + return self.__block + + def to_json(self): + return dumps({question.identifier: question.answer.value.get_json_value() for question in self.block}) + + def find_question_of_widget(self, widget): + for question in self.block: + if question.widget == widget: + return question + + def update_questions_on_change(self, changed_widget): + changed_question = self.find_question_of_widget(changed_widget) + + if changed_question: + new_value = changed_question.widget.get_value(changed_question.answer_type) + changed_question.answer = changed_question.answer_type.get_literal_node(new_value) + + for question in self.block: + result = question.evaluate_visibility_condition(self) + + if result: + question.widget.show() + question.widget_label.show() + else: + question.widget.hide() + question.widget_label.hide() + + if question.computed: + answer_result = str(question.evaluate_answer(self)) + question.widget.setText(answer_result) diff --git a/gui/model/question.py b/gui/model/question.py new file mode 100644 index 0000000..a45d6e2 --- /dev/null +++ b/gui/model/question.py @@ -0,0 +1,83 @@ +from gui.widgets.label import Label +from ql.ast.visitors.expression_evaluator import ExpressionEvaluator + + +class QuestionModel: + def __init__(self, label, identifier, answer_type, answer, computed, visibility_condition): + self.__label = label + self.__identifier = identifier + self.__answer_type = answer_type + self.__answer = answer + self.__computed = computed + self.__visibility_condition = visibility_condition + self.__widget = None + self.__widget_label = None + + @property + def label(self): + return self.__label + + @property + def identifier(self): + return self.__identifier + + @property + def answer_type(self): + return self.__answer_type + + @property + def answer(self): + return self.__answer + + @answer.setter + def answer(self, value): + self.__answer = value + + @property + def computed(self): + return self.__computed + + @property + def visibility_condition(self): + return self.__visibility_condition + + @property + def widget(self): + return self.__widget + + @widget.setter + def widget(self, value): + self.__widget = value + + @property + def widget_label(self): + return self.__widget_label + + @widget_label.setter + def widget_label(self, value): + self.__widget_label = value + + def evaluate_visibility_condition(self, form): + visitor = ExpressionEvaluator(form) + visitor.visit(self.visibility_condition) + return visitor.result + + def evaluate_answer(self, form): + visitor = ExpressionEvaluator(form) + visitor.visit(self.answer) + return visitor.result + + def pyqt5_render(self, layout, form, visible=True): + self.widget_label = Label(self.label) + + if self.computed: + answer_result = str(self.evaluate_answer(form)) + self.widget = Label(answer_result) + else: + self.widget = self.answer_type.pyqt5_default_widget() + + if not visible: + self.widget.hide() + self.widget_label.hide() + + layout.addRow(self.widget_label, self.widget) diff --git a/gui/widgets/__pycache__/calendar.cpython-35.pyc b/gui/widgets/__pycache__/calendar.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..fcd150c --- /dev/null +++ b/gui/widgets/__pycache__/calendar.cpython-35.pyc diff --git a/gui/widgets/__pycache__/checkbox.cpython-35.pyc b/gui/widgets/__pycache__/checkbox.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..49f87fc --- /dev/null +++ b/gui/widgets/__pycache__/checkbox.cpython-35.pyc diff --git a/gui/widgets/__pycache__/double_spinbox.cpython-35.pyc b/gui/widgets/__pycache__/double_spinbox.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..31d21df --- /dev/null +++ b/gui/widgets/__pycache__/double_spinbox.cpython-35.pyc diff --git a/gui/widgets/__pycache__/label.cpython-35.pyc b/gui/widgets/__pycache__/label.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..13726bf --- /dev/null +++ b/gui/widgets/__pycache__/label.cpython-35.pyc diff --git a/gui/widgets/__pycache__/line_edit.cpython-35.pyc b/gui/widgets/__pycache__/line_edit.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..8b314d1 --- /dev/null +++ b/gui/widgets/__pycache__/line_edit.cpython-35.pyc diff --git a/gui/widgets/__pycache__/money_spinbox.cpython-35.pyc b/gui/widgets/__pycache__/money_spinbox.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..f55f3da --- /dev/null +++ b/gui/widgets/__pycache__/money_spinbox.cpython-35.pyc diff --git a/gui/widgets/__pycache__/spinbox.cpython-35.pyc b/gui/widgets/__pycache__/spinbox.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..d23e28b --- /dev/null +++ b/gui/widgets/__pycache__/spinbox.cpython-35.pyc diff --git a/gui/widgets/calendar.py b/gui/widgets/calendar.py new file mode 100644 index 0000000..5f09834 --- /dev/null +++ b/gui/widgets/calendar.py @@ -0,0 +1,13 @@ +from PyQt5.QtWidgets import QCalendarWidget + + +class CalendarWidget(QCalendarWidget): + def __init__(self): + super(QCalendarWidget, self).__init__() + + def get_value(self, ql_type): + date = self.selectedDate() + return ql_type(date.day(), date.month(), date.year()) + + def on_change(self, change_event_function): + self.selectionChanged.connect(lambda: change_event_function(self)) diff --git a/gui/widgets/checkbox.py b/gui/widgets/checkbox.py new file mode 100644 index 0000000..d8e32f1 --- /dev/null +++ b/gui/widgets/checkbox.py @@ -0,0 +1,12 @@ +from PyQt5.QtWidgets import QCheckBox + + +class CheckBox(QCheckBox): + def __init__(self): + super(QCheckBox, self).__init__() + + def get_value(self, ql_type): + return ql_type(self.isChecked()) + + def on_change(self, change_event_function): + self.stateChanged.connect(lambda: change_event_function(self)) diff --git a/gui/widgets/double_spinbox.py b/gui/widgets/double_spinbox.py new file mode 100644 index 0000000..bde201d --- /dev/null +++ b/gui/widgets/double_spinbox.py @@ -0,0 +1,15 @@ +from PyQt5.QtWidgets import QDoubleSpinBox + + +class DoubleSpinBox(QDoubleSpinBox): + def __init__(self): + super(QDoubleSpinBox, self).__init__() + self.setMaximum(2**31 - 1) + self.setMinimum(-self.maximum()) + self.setDecimals(16) + + def get_value(self, ql_type): + return ql_type(self.value()) + + def on_change(self, change_event_function): + self.valueChanged.connect(lambda: change_event_function(self)) diff --git a/gui/widgets/label.py b/gui/widgets/label.py new file mode 100644 index 0000000..a0ce233 --- /dev/null +++ b/gui/widgets/label.py @@ -0,0 +1,9 @@ +from PyQt5.QtWidgets import QLabel + + +class Label(QLabel): + def __init__(self, label): + super(QLabel, self).__init__(label) + + def on_change(self, change_event_function): + pass diff --git a/gui/widgets/line_edit.py b/gui/widgets/line_edit.py new file mode 100644 index 0000000..a87a7b6 --- /dev/null +++ b/gui/widgets/line_edit.py @@ -0,0 +1,12 @@ +from PyQt5.QtWidgets import QLineEdit + + +class LineEdit(QLineEdit): + def __init__(self): + super(QLineEdit, self).__init__() + + def get_value(self, ql_type): + return ql_type(self.text()) + + def on_change(self, change_event_function): + self.textChanged.connect(lambda: change_event_function(self)) diff --git a/gui/widgets/money_spinbox.py b/gui/widgets/money_spinbox.py new file mode 100644 index 0000000..680a432 --- /dev/null +++ b/gui/widgets/money_spinbox.py @@ -0,0 +1,15 @@ +from PyQt5.QtWidgets import QDoubleSpinBox + + +class MoneySpinbox(QDoubleSpinBox): + def __init__(self): + super(QDoubleSpinBox, self).__init__() + self.setPrefix('$') + self.setMaximum(2**31 - 1) + self.setMinimum(-self.maximum()) + + def get_value(self, ql_type): + return ql_type(self.value(), self.prefix()) + + def on_change(self, change_event_function): + self.valueChanged.connect(lambda: change_event_function(self)) diff --git a/gui/widgets/spinbox.py b/gui/widgets/spinbox.py new file mode 100644 index 0000000..1abb63a --- /dev/null +++ b/gui/widgets/spinbox.py @@ -0,0 +1,14 @@ +from PyQt5.QtWidgets import QSpinBox + + +class SpinBox(QSpinBox): + def __init__(self): + super(QSpinBox, self).__init__() + self.setMaximum(2**31 - 1) + self.setMinimum(-self.maximum()) + + def get_value(self, ql_type): + return ql_type(self.value()) + + def on_change(self, change_event_function): + self.valueChanged.connect(lambda: change_event_function(self)) diff --git a/gui/windows/__pycache__/form.cpython-35.pyc b/gui/windows/__pycache__/form.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..d04e617 --- /dev/null +++ b/gui/windows/__pycache__/form.cpython-35.pyc diff --git a/gui/windows/__pycache__/main.cpython-35.pyc b/gui/windows/__pycache__/main.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..3e7dec3 --- /dev/null +++ b/gui/windows/__pycache__/main.cpython-35.pyc diff --git a/gui/windows/form.py b/gui/windows/form.py new file mode 100644 index 0000000..64c05f8 --- /dev/null +++ b/gui/windows/form.py @@ -0,0 +1,68 @@ +from PyQt5.QtCore import pyqtSlot +from PyQt5.QtWidgets import QDialog +from PyQt5.QtWidgets import QDialogButtonBox +from PyQt5.QtWidgets import QFileDialog +from PyQt5.QtWidgets import QFormLayout +from PyQt5.QtWidgets import QGroupBox +from PyQt5.QtWidgets import QMessageBox +from PyQt5.QtWidgets import QVBoxLayout + +from gui.helper import append_file_extension + + +class FormWindow(QDialog): + def __init__(self, form_model): + super(FormWindow, self).__init__() + self.__form_model = form_model + self.__form_group_box = QGroupBox() + + self.setWindowTitle('Form') + self.create_form() + + button_box = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Cancel) + button_box.accepted.connect(self.accept) + button_box.rejected.connect(self.reject) + + main_layout = QVBoxLayout() + main_layout.addWidget(self.form_group_box) + main_layout.addWidget(button_box) + self.setLayout(main_layout) + + @property + def form_model(self): + return self.__form_model + + @property + def form_group_box(self): + return self.__form_group_box + + def create_form(self): + layout = QFormLayout() + + for question in self.form_model.block: + show = question.evaluate_visibility_condition(self.form_model) + question.pyqt5_render(layout, self.form_model, show) + question.widget.on_change(self.form_model.update_questions_on_change) + + self.form_group_box.setLayout(layout) + + @pyqtSlot(name='accept') + def accept(self): + file_name, _ = QFileDialog.getSaveFileName(QFileDialog(), 'Save results', self.form_model.identifier, + 'JSON (*.json);;All Files (*)') + + if file_name: + file_name = append_file_extension(file_name, 'json') + file = open(file_name, 'w') + file.write(self.form_model.to_json()) + file.close() + self.close() + QMessageBox.information(QMessageBox(), 'Submission', 'Your answers have been submitted successfully.', + QMessageBox.Close, QMessageBox.Escape) + else: + QMessageBox.warning(QMessageBox(), 'Warning', 'Questionnaire results were not saved.', + QMessageBox.Close, QMessageBox.Escape) + + @pyqtSlot(name='reject') + def reject(self): + self.hide() diff --git a/gui/windows/main.py b/gui/windows/main.py new file mode 100644 index 0000000..4dc4ef2 --- /dev/null +++ b/gui/windows/main.py @@ -0,0 +1,139 @@ +from PyQt5.QtGui import QIcon
+from PyQt5.QtWidgets import QAction
+from PyQt5.QtWidgets import QFileDialog
+from PyQt5.QtWidgets import QMainWindow
+from PyQt5.QtWidgets import QTextEdit
+
+from gui.helper import append_file_extension
+from gui.helper import check_errors
+from gui.helper import warning
+from gui.windows.form import FormWindow
+from ql.ast.checkers.dependency_checker import DependencyChecker
+from ql.ast.checkers.question_checker import QuestionChecker
+from ql.ast.checkers.reference_checker import ReferenceChecker
+from ql.ast.extractors.extractor import extract_gui_model
+from ql.ast.extractors.extractor import extract_identifier_dependencies
+from ql.ast.extractors.extractor import extract_identifier_scopes
+from ql.ast.extractors.extractor import extract_identifier_types
+from ql.ast.extractors.extractor import extract_questions
+from ql.ast.visitors.type_visitor import TypeVisitor
+from ql.parser.lexer import QLLexer
+from ql.parser.parser import QLParser
+
+
+class MainWindow(QMainWindow):
+ def __init__(self):
+ super().__init__()
+
+ self.setWindowTitle('PyQuest')
+ self.current_file = None
+ self.create_menu_bar()
+ self.text_edit = QTextEdit()
+ self.setCentralWidget(self.text_edit)
+
+ self.show()
+
+ def create_menu_bar(self):
+ menu_bar = self.menuBar()
+
+ new_file = QAction(QIcon(), 'New', self)
+ new_file.setShortcut('Ctrl+N')
+ new_file.setStatusTip('New file')
+ new_file.triggered.connect(self.new_file)
+
+ open_file = QAction(QIcon(), 'Open', self)
+ open_file.setShortcut('Ctrl+O')
+ open_file.setStatusTip('Open file')
+ open_file.triggered.connect(self.open_file)
+
+ save = QAction(QIcon(), 'Save', self)
+ save.setShortcut('Ctrl+S')
+ save.setStatusTip('Save file')
+ save.triggered.connect(self.save)
+
+ save_file = QAction(QIcon(), 'Save as', self)
+ save_file.setShortcut('Ctrl+Shift+S')
+ save_file.setStatusTip('Save file as')
+ save_file.triggered.connect(self.save_file)
+
+ create_form = QAction(QIcon(), 'Create form', self)
+ create_form.setShortcut('Ctrl+R')
+ create_form.setStatusTip('Create form')
+ create_form.triggered.connect(self.create_form)
+
+ file_menu = menu_bar.addMenu('&File')
+ file_menu.addAction(new_file)
+ file_menu.addAction(open_file)
+ file_menu.addAction(save)
+ file_menu.addAction(save_file)
+
+ create_menu = menu_bar.addMenu('&Create')
+ create_menu.addAction(create_form)
+
+ def new_file(self):
+ self.current_file = None
+ self.text_edit.setText('')
+
+ def open_file(self):
+ self.current_file, _ = QFileDialog.getOpenFileName(caption='Open file', directory='/home',
+ filter="Questionnaire language files (*.ql)")
+
+ if self.current_file:
+ with open(self.current_file, 'r') as file:
+ self.text_edit.setText(file.read())
+
+ def save(self):
+ if self.current_file:
+ with open(self.current_file, 'w') as file:
+ file.write(self.text_edit.toPlainText())
+ else:
+ self.save_file()
+
+ def save_file(self):
+ file_name, _ = QFileDialog.getSaveFileName(caption='Save file as', directory='/home',
+ filter='Questionnaire language files (*.ql)')
+
+ if file_name:
+ self.current_file = append_file_extension(file_name, 'ql')
+ with open(self.current_file, 'w') as file:
+ file.write(self.text_edit.toPlainText())
+
+ def create_form(self):
+ textbox_value = self.text_edit.toPlainText()
+ ql_lexer = QLLexer()
+ ql_lexer.build()
+ ql_parser = QLParser()
+ ql_parser.build()
+ empty_form = []
+
+ if not textbox_value:
+ empty_form.append('Empty Form')
+
+ try:
+ check_errors(empty_form)
+ ast = ql_parser.parse(textbox_value, ql_lexer.lexer)
+ parse_errors = ql_parser.errors
+
+ check_errors(parse_errors)
+ reference_errors = ReferenceChecker(extract_identifier_scopes(ast)).errors
+
+ check_errors(reference_errors)
+ dependency_errors = DependencyChecker(extract_identifier_dependencies(ast)).errors
+
+ check_errors(dependency_errors)
+ question_errors = QuestionChecker(extract_questions(ast)).errors
+ question_warnings = QuestionChecker(extract_questions(ast)).warnings
+
+ if question_warnings:
+ warning(question_warnings)
+
+ check_errors(question_errors)
+ type_visitor = TypeVisitor(extract_identifier_types(ast))
+ type_visitor.visit(ast)
+ type_errors = type_visitor.errors
+
+ check_errors(type_errors),
+ dialog = FormWindow(extract_gui_model(ast))
+ dialog.exec_()
+ except SyntaxError:
+ print('Consult application popup error window for information on what went wrong.')
diff --git a/pyquest.py b/pyquest.py new file mode 100644 index 0000000..caf0726 --- /dev/null +++ b/pyquest.py @@ -0,0 +1,43 @@ +from argparse import ArgumentParser +from sys import argv +from sys import exit + +from PyQt5.QtWidgets import QApplication + +from gui.windows.main import MainWindow +from ql.parser.lexer import QLLexer +from ql.parser.parser import QLParser +from ql.test.expression_evaluation.test_expression_evaluation import TestExpressionEvaluation +from ql.test.lexing.test_lexing import TestLexing +from ql.test.parsing.test_parsing import TestParsing +from ql.test.semantic_analysis.test_semantic_analysis import TestSemanticAnalysis + + +def main(): + parser = ArgumentParser(prog='PyQuest') + parser.add_argument('-t', '--test', action='store_true', help="Perform tests.") + arguments = parser.parse_args() + + if arguments.test: + ql_lexer = QLLexer() + ql_lexer.build() + ql_parser = QLParser() + ql_parser.build() + + test_lexer = TestLexing('ql/test/lexing/', ql_lexer) + test_parser = TestParsing('ql/test/parsing/', ql_lexer, ql_parser) + test_semantic_analyzer = TestSemanticAnalysis('ql/test/semantic_analysis/', ql_lexer, ql_parser) + test_evaluation = TestExpressionEvaluation('ql/test/expression_evaluation/', ql_lexer, ql_parser) + + test_lexer.test() + test_parser.test() + test_semantic_analyzer.test() + test_evaluation.test() + else: + application = QApplication(argv) + main_window = MainWindow() + exit(application.exec_()) + + +if __name__ == '__main__': + main() diff --git a/ql/ast/checkers/__pycache__/dependency_checker.cpython-35.pyc b/ql/ast/checkers/__pycache__/dependency_checker.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..5be2eb2 --- /dev/null +++ b/ql/ast/checkers/__pycache__/dependency_checker.cpython-35.pyc diff --git a/ql/ast/checkers/__pycache__/question_checker.cpython-35.pyc b/ql/ast/checkers/__pycache__/question_checker.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..bb81f4a --- /dev/null +++ b/ql/ast/checkers/__pycache__/question_checker.cpython-35.pyc diff --git a/ql/ast/checkers/__pycache__/reference_checker.cpython-35.pyc b/ql/ast/checkers/__pycache__/reference_checker.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..3bdfae5 --- /dev/null +++ b/ql/ast/checkers/__pycache__/reference_checker.cpython-35.pyc diff --git a/ql/ast/checkers/dependency_checker.py b/ql/ast/checkers/dependency_checker.py new file mode 100644 index 0000000..473ef6b --- /dev/null +++ b/ql/ast/checkers/dependency_checker.py @@ -0,0 +1,44 @@ +class DependencyChecker: + def __init__(self, combinations): + self.__errors = [] + self.__check_dependencies(combinations) + + @property + def errors(self): + return self.__errors + + def __check_dependencies(self, combinations): + for (identifier, identifier_children, identifier_metadata) in combinations: + children = self.__find_children(identifier, combinations) + + if identifier in children: + self.__errors.append('Cyclic dependency detected in question identifiers on line(s) {}' + .format(str(self.__find_lines(children, combinations))[1:-1])) + + def __find_children(self, identifier, combinations): + reference, reference_children, _ = combinations[0] + + if len(combinations) == 1 and identifier == reference: + return reference_children + elif len(combinations) == 1: + return [] + elif identifier == reference: + all_children = [] + + for new_identifier in reference_children: + all_children += self.__find_children(new_identifier, combinations[1:]) + + return all_children + reference_children + + return self.__find_children(identifier, combinations[1:]) + + @staticmethod + def __find_lines(children, combinations): + lines = [] + + for identifier, _, metadata in combinations: + for child in children: + if identifier == child: + lines.append(metadata.line) + + return lines diff --git a/ql/ast/checkers/question_checker.py b/ql/ast/checkers/question_checker.py new file mode 100644 index 0000000..5b255d8 --- /dev/null +++ b/ql/ast/checkers/question_checker.py @@ -0,0 +1,33 @@ +class QuestionChecker: + def __init__(self, questions): + self.__errors = [] + self.__warnings = [] + self.__check_questions(questions) + + @property + def errors(self): + return self.__errors + + @property + def warnings(self): + return self.__warnings + + def __check_questions(self, questions): + for question1 in questions: + for question2 in questions: + if question1 != question2: + equal_labels = question1['label'] == question2['label'] + equal_identifiers = question1['identifier'] == question2['identifier'] + different_types = question1['answer_type'] != question2['answer_type'] + + if all([equal_labels, equal_identifiers, different_types]): + self.__errors.append('Duplicate questions with different types found on lines {} and {}' + .format(question1['metadata'].line, question2['metadata'].line)) + + if equal_identifiers: + self.__errors.append('Duplicate question identifiers found on lines {} and {}' + .format(question1['metadata'].line, question2['metadata'].line)) + + if equal_labels: + self.__warnings.append('Duplicate question labels found on lines {} and {}' + .format(question1['metadata'].line, question2['metadata'].line)) diff --git a/ql/ast/checkers/reference_checker.py b/ql/ast/checkers/reference_checker.py new file mode 100644 index 0000000..71407c3 --- /dev/null +++ b/ql/ast/checkers/reference_checker.py @@ -0,0 +1,30 @@ +class ReferenceChecker: + def __init__(self, table): + self.__errors = [] + self.__check_references(table, [], []) + + @property + def errors(self): + return self.__errors + + def __check_references(self, table, known_types, unknown_types): + (local_known_types, local_unknown_types) = self.__split_known_unknown_types(table) + known_types += local_known_types + unknown_types += local_unknown_types + + self.__identifier_seen(known_types, unknown_types) + + if table['children']: + for child_scope in table['children']: + self.__check_references(child_scope, known_types, unknown_types) + + @staticmethod + def __split_known_unknown_types(table): + known_types = [row['name'] for row in table['content'] if row['type']] + unknown_types = [(row['name'], row['line']) for row in table['content'] if not (row['type'])] + return known_types, unknown_types + + def __identifier_seen(self, known_types, unknown_types): + for (identifier, line) in unknown_types: + if not (identifier in known_types): + self.__errors.append('Identifier \"{}\" at line {} is unknown'.format(identifier, line)) diff --git a/ql/ast/extractors/__pycache__/extractor.cpython-35.pyc b/ql/ast/extractors/__pycache__/extractor.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..ceb2379 --- /dev/null +++ b/ql/ast/extractors/__pycache__/extractor.cpython-35.pyc diff --git a/ql/ast/extractors/extractor.py b/ql/ast/extractors/extractor.py new file mode 100644 index 0000000..f86304e --- /dev/null +++ b/ql/ast/extractors/extractor.py @@ -0,0 +1,35 @@ +from ql.ast.visitors.dependency_visitor import DependencyVisitor +from ql.ast.visitors.identifier_type_visitor import IdentifierTypeVisitor +from ql.ast.visitors.model_generator import ModelGenerator +from ql.ast.visitors.question_visitor import QuestionVisitor +from ql.ast.visitors.reference_visitor import ReferenceVisitor + + +def extract_identifier_dependencies(ast): + dependency_visitor = DependencyVisitor() + dependency_visitor.visit(ast) + return dependency_visitor.identifier_dependencies + + +def extract_identifier_scopes(ast): + reference_visitor = ReferenceVisitor() + reference_visitor.visit(ast) + return reference_visitor.identifier_scopes + + +def extract_identifier_types(ast): + identifier_type_visitor = IdentifierTypeVisitor() + identifier_type_visitor.visit(ast) + return identifier_type_visitor.symbol_table + + +def extract_questions(ast): + question_visitor = QuestionVisitor() + question_visitor.visit(ast) + return question_visitor.questions + + +def extract_gui_model(ast): + model_generator = ModelGenerator() + model_generator.visit(ast) + return model_generator.form diff --git a/ql/ast/nodes/__pycache__/base.cpython-35.pyc b/ql/ast/nodes/__pycache__/base.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..d1f8e50 --- /dev/null +++ b/ql/ast/nodes/__pycache__/base.cpython-35.pyc diff --git a/ql/ast/nodes/base.py b/ql/ast/nodes/base.py new file mode 100644 index 0000000..d9196f9 --- /dev/null +++ b/ql/ast/nodes/base.py @@ -0,0 +1,10 @@ +class BaseNode: + def __init__(self, metadata): + self.__metadata = metadata + + def accept(self, visitor): + visitor.visit(self) + + @property + def metadata(self): + return self.__metadata diff --git a/ql/ast/nodes/expressions/__pycache__/expression.cpython-35.pyc b/ql/ast/nodes/expressions/__pycache__/expression.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..84ede5c --- /dev/null +++ b/ql/ast/nodes/expressions/__pycache__/expression.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/__pycache__/variable.cpython-35.pyc b/ql/ast/nodes/expressions/__pycache__/variable.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..b4ff8dc --- /dev/null +++ b/ql/ast/nodes/expressions/__pycache__/variable.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/addition_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/addition_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..bbc8130 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/addition_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/and_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/and_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..f004296 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/and_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/binary_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/binary_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..18d3fc0 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/binary_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/division_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/division_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..9cd8e0a --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/division_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/equals_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/equals_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..5d48766 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/equals_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/greater_equals_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/greater_equals_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..888c85c --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/greater_equals_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/greater_than_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/greater_than_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..be0e395 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/greater_than_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/less_equals_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/less_equals_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..b7e8155 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/less_equals_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/less_than_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/less_than_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..850a39c --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/less_than_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/multiplication_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/multiplication_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..ff0e1ab --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/multiplication_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/not_equals_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/not_equals_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..fe666cf --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/not_equals_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/or_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/or_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..0b81fc3 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/or_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/__pycache__/subtraction_operator.cpython-35.pyc b/ql/ast/nodes/expressions/binary_operators/__pycache__/subtraction_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..cd89879 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/__pycache__/subtraction_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/binary_operators/addition_operator.py b/ql/ast/nodes/expressions/binary_operators/addition_operator.py new file mode 100644 index 0000000..d6e4506 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/addition_operator.py @@ -0,0 +1,27 @@ +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.types.decimal import QLDecimal +from ql.types.integer import QLInteger +from ql.types.money import QLMoney +from ql.types.undefined import QLUndefined + + +class AdditionOperatorNode(BinaryOperatorNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(AdditionOperatorNode, self).__init__(metadata, expression_type, + left_expression, right_expression, value) + self.__valid_types = { + (QLDecimal, QLDecimal): QLDecimal, + (QLDecimal, QLInteger): QLDecimal, + (QLInteger, QLInteger): QLInteger, + (QLInteger, QLDecimal): QLDecimal, + (QLMoney, QLMoney): QLMoney, + } + + def get_result_type(self): + if self.__valid_types.get((self.left_expression.expression_type, self.right_expression.expression_type)): + return self.__valid_types.get((self.left_expression.expression_type, self.right_expression.expression_type)) + + return QLUndefined + + def evaluate(self): + self.value = self.left_expression.value + self.right_expression.value diff --git a/ql/ast/nodes/expressions/binary_operators/and_operator.py b/ql/ast/nodes/expressions/binary_operators/and_operator.py new file mode 100644 index 0000000..5981a6b --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/and_operator.py @@ -0,0 +1,21 @@ +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.types.boolean import QLBoolean +from ql.types.undefined import QLUndefined + + +class AndOperatorNode(BinaryOperatorNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(AndOperatorNode, self).__init__(metadata, expression_type, + left_expression, right_expression, value) + self.__valid_types = { + (QLBoolean, QLBoolean): QLBoolean, + } + + def get_result_type(self): + if self.__valid_types.get((self.left_expression.expression_type, self.right_expression.expression_type)): + return self.__valid_types.get((self.left_expression.expression_type, self.right_expression.expression_type)) + + return QLUndefined + + def evaluate(self): + self.value = self.left_expression.value and self.right_expression.value diff --git a/ql/ast/nodes/expressions/binary_operators/binary_operator.py b/ql/ast/nodes/expressions/binary_operators/binary_operator.py new file mode 100644 index 0000000..048d927 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/binary_operator.py @@ -0,0 +1,17 @@ +from ql.ast.nodes.expressions.expression import ExpressionNode + + +class BinaryOperatorNode(ExpressionNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(BinaryOperatorNode, self).__init__(metadata, expression_type, value) + self.__left_expression = left_expression + self.__right_expression = right_expression + + @property + def left_expression(self): + return self.__left_expression + + @property + def right_expression(self): + return self.__right_expression + diff --git a/ql/ast/nodes/expressions/binary_operators/division_operator.py b/ql/ast/nodes/expressions/binary_operators/division_operator.py new file mode 100644 index 0000000..16d5063 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/division_operator.py @@ -0,0 +1,31 @@ +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.types.decimal import QLDecimal +from ql.types.integer import QLInteger +from ql.types.money import QLMoney +from ql.types.undefined import QLUndefined + + +class DivisionOperatorNode(BinaryOperatorNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(DivisionOperatorNode, self).__init__(metadata, expression_type, + left_expression, right_expression, value) + self.__valid_types = { + (QLDecimal, QLDecimal): QLDecimal, + (QLDecimal, QLInteger): QLDecimal, + (QLInteger, QLInteger): QLDecimal, + (QLInteger, QLDecimal): QLDecimal, + (QLMoney, QLDecimal): QLMoney, + (QLMoney, QLInteger): QLMoney, + } + + def get_result_type(self): + if self.__valid_types.get((self.left_expression.expression_type, self.right_expression.expression_type)): + return self.__valid_types.get((self.left_expression.expression_type, self.right_expression.expression_type)) + + return QLUndefined + + def evaluate(self): + try: + self.value = self.left_expression.value / self.right_expression.value + except ZeroDivisionError: + self.value = QLUndefined() diff --git a/ql/ast/nodes/expressions/binary_operators/equals_operator.py b/ql/ast/nodes/expressions/binary_operators/equals_operator.py new file mode 100644 index 0000000..21315f9 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/equals_operator.py @@ -0,0 +1,15 @@ +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.types.boolean import QLBoolean + + +class EqualsOperatorNode(BinaryOperatorNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(EqualsOperatorNode, self).__init__(metadata, expression_type, + left_expression, right_expression, value) + + @staticmethod + def get_result_type(): + return QLBoolean + + def evaluate(self): + self.value = self.left_expression.value == self.right_expression.value diff --git a/ql/ast/nodes/expressions/binary_operators/greater_equals_operator.py b/ql/ast/nodes/expressions/binary_operators/greater_equals_operator.py new file mode 100644 index 0000000..0512688 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/greater_equals_operator.py @@ -0,0 +1,30 @@ +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.types.boolean import QLBoolean +from ql.types.date import QLDate +from ql.types.decimal import QLDecimal +from ql.types.integer import QLInteger +from ql.types.money import QLMoney +from ql.types.undefined import QLUndefined + + +class GreaterEqualsOperatorNode(BinaryOperatorNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(GreaterEqualsOperatorNode, self).__init__(metadata, expression_type, + left_expression, right_expression, value) + self.__valid_types = [ + (QLDate, QLDate), + (QLDecimal, QLDecimal), + (QLDecimal, QLInteger), + (QLInteger, QLInteger), + (QLInteger, QLDecimal), + (QLMoney, QLMoney), + ] + + def get_result_type(self): + if (self.left_expression.expression_type, self.right_expression.expression_type) in self.__valid_types: + return QLBoolean + + return QLUndefined + + def evaluate(self): + self.value = self.left_expression.value >= self.right_expression.value diff --git a/ql/ast/nodes/expressions/binary_operators/greater_than_operator.py b/ql/ast/nodes/expressions/binary_operators/greater_than_operator.py new file mode 100644 index 0000000..460c909 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/greater_than_operator.py @@ -0,0 +1,30 @@ +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.types.boolean import QLBoolean +from ql.types.date import QLDate +from ql.types.decimal import QLDecimal +from ql.types.integer import QLInteger +from ql.types.money import QLMoney +from ql.types.undefined import QLUndefined + + +class GreaterThanOperatorNode(BinaryOperatorNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(GreaterThanOperatorNode, self).__init__(metadata, expression_type, + left_expression, right_expression, value) + self.__valid_types = [ + (QLDate, QLDate), + (QLDecimal, QLDecimal), + (QLDecimal, QLInteger), + (QLInteger, QLInteger), + (QLInteger, QLDecimal), + (QLMoney, QLMoney), + ] + + def get_result_type(self): + if (self.left_expression.expression_type, self.right_expression.expression_type) in self.__valid_types: + return QLBoolean + + return QLUndefined + + def evaluate(self): + self.value = self.left_expression.value > self.right_expression.value diff --git a/ql/ast/nodes/expressions/binary_operators/less_equals_operator.py b/ql/ast/nodes/expressions/binary_operators/less_equals_operator.py new file mode 100644 index 0000000..f5b86df --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/less_equals_operator.py @@ -0,0 +1,30 @@ +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.types.boolean import QLBoolean +from ql.types.date import QLDate +from ql.types.decimal import QLDecimal +from ql.types.integer import QLInteger +from ql.types.money import QLMoney +from ql.types.undefined import QLUndefined + + +class LessEqualsOperatorNode(BinaryOperatorNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(LessEqualsOperatorNode, self).__init__(metadata, expression_type, + left_expression, right_expression, value) + self.__valid_types = [ + (QLDate, QLDate), + (QLDecimal, QLDecimal), + (QLDecimal, QLInteger), + (QLInteger, QLInteger), + (QLInteger, QLDecimal), + (QLMoney, QLMoney), + ] + + def get_result_type(self): + if (self.left_expression.expression_type, self.right_expression.expression_type) in self.__valid_types: + return QLBoolean + + return QLUndefined + + def evaluate(self): + self.value = self.left_expression.value <= self.right_expression.value diff --git a/ql/ast/nodes/expressions/binary_operators/less_than_operator.py b/ql/ast/nodes/expressions/binary_operators/less_than_operator.py new file mode 100644 index 0000000..65b456d --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/less_than_operator.py @@ -0,0 +1,30 @@ +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.types.boolean import QLBoolean +from ql.types.date import QLDate +from ql.types.decimal import QLDecimal +from ql.types.integer import QLInteger +from ql.types.money import QLMoney +from ql.types.undefined import QLUndefined + + +class LessThanOperatorNode(BinaryOperatorNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(LessThanOperatorNode, self).__init__(metadata, expression_type, + left_expression, right_expression, value) + self.__valid_types = [ + (QLDate, QLDate), + (QLDecimal, QLDecimal), + (QLDecimal, QLInteger), + (QLInteger, QLInteger), + (QLInteger, QLDecimal), + (QLMoney, QLMoney), + ] + + def get_result_type(self): + if (self.left_expression.expression_type, self.right_expression.expression_type) in self.__valid_types: + return QLBoolean + + return QLUndefined + + def evaluate(self): + self.value = self.left_expression.value < self.right_expression.value diff --git a/ql/ast/nodes/expressions/binary_operators/multiplication_operator.py b/ql/ast/nodes/expressions/binary_operators/multiplication_operator.py new file mode 100644 index 0000000..b014c0e --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/multiplication_operator.py @@ -0,0 +1,30 @@ +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.types.decimal import QLDecimal +from ql.types.integer import QLInteger +from ql.types.money import QLMoney +from ql.types.undefined import QLUndefined + + +class MultiplicationOperatorNode(BinaryOperatorNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(MultiplicationOperatorNode, self).__init__(metadata, expression_type, + left_expression, right_expression, value) + self.__valid_types = { + (QLDecimal, QLDecimal): QLDecimal, + (QLDecimal, QLInteger): QLDecimal, + (QLDecimal, QLMoney): QLMoney, + (QLInteger, QLInteger): QLInteger, + (QLInteger, QLDecimal): QLDecimal, + (QLInteger, QLMoney): QLMoney, + (QLMoney, QLDecimal): QLMoney, + (QLMoney, QLInteger): QLMoney, + } + + def get_result_type(self): + if self.__valid_types.get((self.left_expression.expression_type, self.right_expression.expression_type)): + return self.__valid_types.get((self.left_expression.expression_type, self.right_expression.expression_type)) + + return QLUndefined + + def evaluate(self): + self.value = self.left_expression.value * self.right_expression.value diff --git a/ql/ast/nodes/expressions/binary_operators/not_equals_operator.py b/ql/ast/nodes/expressions/binary_operators/not_equals_operator.py new file mode 100644 index 0000000..3be2e5f --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/not_equals_operator.py @@ -0,0 +1,15 @@ +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.types.boolean import QLBoolean + + +class NotEqualsOperatorNode(BinaryOperatorNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(NotEqualsOperatorNode, self).__init__(metadata, expression_type, + left_expression, right_expression, value) + + @staticmethod + def get_result_type(): + return QLBoolean + + def evaluate(self): + self.value = self.left_expression.value != self.right_expression.value diff --git a/ql/ast/nodes/expressions/binary_operators/or_operator.py b/ql/ast/nodes/expressions/binary_operators/or_operator.py new file mode 100644 index 0000000..4314868 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/or_operator.py @@ -0,0 +1,21 @@ +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.types.boolean import QLBoolean +from ql.types.undefined import QLUndefined + + +class OrOperatorNode(BinaryOperatorNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(OrOperatorNode, self).__init__(metadata, expression_type, + left_expression, right_expression, value) + self.__valid_types = { + (QLBoolean, QLBoolean): QLBoolean, + } + + def get_result_type(self): + if self.__valid_types.get((self.left_expression.expression_type, self.right_expression.expression_type)): + return self.__valid_types.get((self.left_expression.expression_type, self.right_expression.expression_type)) + + return QLUndefined + + def evaluate(self): + self.value = self.left_expression.value or self.right_expression.value diff --git a/ql/ast/nodes/expressions/binary_operators/subtraction_operator.py b/ql/ast/nodes/expressions/binary_operators/subtraction_operator.py new file mode 100644 index 0000000..8ebda15 --- /dev/null +++ b/ql/ast/nodes/expressions/binary_operators/subtraction_operator.py @@ -0,0 +1,27 @@ +from ql.ast.nodes.expressions.binary_operators.binary_operator import BinaryOperatorNode +from ql.types.decimal import QLDecimal +from ql.types.integer import QLInteger +from ql.types.money import QLMoney +from ql.types.undefined import QLUndefined + + +class SubtractionOperatorNode(BinaryOperatorNode): + def __init__(self, metadata, expression_type, left_expression, right_expression, value): + super(SubtractionOperatorNode, self).__init__(metadata, expression_type, + left_expression, right_expression, value) + self.__valid_types = { + (QLDecimal, QLDecimal): QLDecimal, + (QLDecimal, QLInteger): QLDecimal, + (QLInteger, QLInteger): QLInteger, + (QLInteger, QLDecimal): QLDecimal, + (QLMoney, QLMoney): QLMoney, + } + + def get_result_type(self): + if self.__valid_types.get((self.left_expression.expression_type, self.right_expression.expression_type)): + return self.__valid_types.get((self.left_expression.expression_type, self.right_expression.expression_type)) + + return QLUndefined + + def evaluate(self): + self.value = self.left_expression.value - self.right_expression.value diff --git a/ql/ast/nodes/expressions/expression.py b/ql/ast/nodes/expressions/expression.py new file mode 100644 index 0000000..1364c0b --- /dev/null +++ b/ql/ast/nodes/expressions/expression.py @@ -0,0 +1,24 @@ +from ql.ast.nodes.base import BaseNode + + +class ExpressionNode(BaseNode): + def __init__(self, metadata, expression_type, value): + super(ExpressionNode, self).__init__(metadata) + self.__expression_type = expression_type + self.__value = value + + @property + def expression_type(self): + return self.__expression_type + + @expression_type.setter + def expression_type(self, value): + self.__expression_type = value + + @property + def value(self): + return self.__value + + @value.setter + def value(self, value): + self.__value = value diff --git a/ql/ast/nodes/expressions/literals/__pycache__/boolean_literal.cpython-35.pyc b/ql/ast/nodes/expressions/literals/__pycache__/boolean_literal.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..a6d43b1 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/__pycache__/boolean_literal.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/literals/__pycache__/date_literal.cpython-35.pyc b/ql/ast/nodes/expressions/literals/__pycache__/date_literal.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..33abf57 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/__pycache__/date_literal.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/literals/__pycache__/decimal_literal.cpython-35.pyc b/ql/ast/nodes/expressions/literals/__pycache__/decimal_literal.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..145ab16 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/__pycache__/decimal_literal.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/literals/__pycache__/integer_literal.cpython-35.pyc b/ql/ast/nodes/expressions/literals/__pycache__/integer_literal.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..33f5c62 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/__pycache__/integer_literal.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/literals/__pycache__/literal.cpython-35.pyc b/ql/ast/nodes/expressions/literals/__pycache__/literal.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..98af8e6 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/__pycache__/literal.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/literals/__pycache__/money_literal.cpython-35.pyc b/ql/ast/nodes/expressions/literals/__pycache__/money_literal.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..9dbf5d0 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/__pycache__/money_literal.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/literals/__pycache__/string_literal.cpython-35.pyc b/ql/ast/nodes/expressions/literals/__pycache__/string_literal.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..dbb3f72 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/__pycache__/string_literal.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/literals/__pycache__/undefined_literal.cpython-35.pyc b/ql/ast/nodes/expressions/literals/__pycache__/undefined_literal.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..73ce02b --- /dev/null +++ b/ql/ast/nodes/expressions/literals/__pycache__/undefined_literal.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/literals/boolean_literal.py b/ql/ast/nodes/expressions/literals/boolean_literal.py new file mode 100644 index 0000000..234e548 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/boolean_literal.py @@ -0,0 +1,6 @@ +from ql.ast.nodes.expressions.literals.literal import LiteralNode + + +class BooleanNode(LiteralNode): + def __init__(self, metadata, expression_type, value): + super(BooleanNode, self).__init__(metadata, expression_type, value) diff --git a/ql/ast/nodes/expressions/literals/date_literal.py b/ql/ast/nodes/expressions/literals/date_literal.py new file mode 100644 index 0000000..971ab58 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/date_literal.py @@ -0,0 +1,6 @@ +from ql.ast.nodes.expressions.literals.literal import LiteralNode + + +class DateNode(LiteralNode): + def __init__(self, metadata, expression_type, value): + super(DateNode, self).__init__(metadata, expression_type, value) diff --git a/ql/ast/nodes/expressions/literals/decimal_literal.py b/ql/ast/nodes/expressions/literals/decimal_literal.py new file mode 100644 index 0000000..7cc4eb5 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/decimal_literal.py @@ -0,0 +1,6 @@ +from ql.ast.nodes.expressions.literals.literal import LiteralNode + + +class DecimalNode(LiteralNode): + def __init__(self, metadata, expression_type, value): + super(DecimalNode, self).__init__(metadata, expression_type, value) diff --git a/ql/ast/nodes/expressions/literals/integer_literal.py b/ql/ast/nodes/expressions/literals/integer_literal.py new file mode 100644 index 0000000..36923f9 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/integer_literal.py @@ -0,0 +1,6 @@ +from ql.ast.nodes.expressions.literals.literal import LiteralNode + + +class IntegerNode(LiteralNode): + def __init__(self, metadata, expression_type, value): + super(IntegerNode, self).__init__(metadata, expression_type, value) diff --git a/ql/ast/nodes/expressions/literals/literal.py b/ql/ast/nodes/expressions/literals/literal.py new file mode 100644 index 0000000..a0e03ae --- /dev/null +++ b/ql/ast/nodes/expressions/literals/literal.py @@ -0,0 +1,14 @@ +from ql.ast.nodes.expressions.expression import ExpressionNode + + +class LiteralNode(ExpressionNode): + def __init__(self, metadata, expression_type, value): + super(LiteralNode, self).__init__(metadata, expression_type, value) + + @ExpressionNode.expression_type.setter + def expression_type(self, unused): + pass + + @ExpressionNode.value.setter + def value(self, unused): + pass diff --git a/ql/ast/nodes/expressions/literals/money_literal.py b/ql/ast/nodes/expressions/literals/money_literal.py new file mode 100644 index 0000000..119e5ff --- /dev/null +++ b/ql/ast/nodes/expressions/literals/money_literal.py @@ -0,0 +1,6 @@ +from ql.ast.nodes.expressions.literals.literal import LiteralNode + + +class MoneyNode(LiteralNode): + def __init__(self, metadata, expression_type, value): + super(MoneyNode, self).__init__(metadata, expression_type, value) diff --git a/ql/ast/nodes/expressions/literals/string_literal.py b/ql/ast/nodes/expressions/literals/string_literal.py new file mode 100644 index 0000000..4fac895 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/string_literal.py @@ -0,0 +1,6 @@ +from ql.ast.nodes.expressions.literals.literal import LiteralNode + + +class StringNode(LiteralNode): + def __init__(self, metadata, expression_type, value): + super(StringNode, self).__init__(metadata, expression_type, value) diff --git a/ql/ast/nodes/expressions/literals/undefined_literal.py b/ql/ast/nodes/expressions/literals/undefined_literal.py new file mode 100644 index 0000000..4109df6 --- /dev/null +++ b/ql/ast/nodes/expressions/literals/undefined_literal.py @@ -0,0 +1,6 @@ +from ql.ast.nodes.expressions.literals.literal import LiteralNode + + +class UndefinedNode(LiteralNode): + def __init__(self, metadata, expression_type, value): + super(UndefinedNode, self).__init__(metadata, expression_type, value) diff --git a/ql/ast/nodes/expressions/unary_operators/__pycache__/negation_operator.cpython-35.pyc b/ql/ast/nodes/expressions/unary_operators/__pycache__/negation_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..9a6e409 --- /dev/null +++ b/ql/ast/nodes/expressions/unary_operators/__pycache__/negation_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/unary_operators/__pycache__/negative_operator.cpython-35.pyc b/ql/ast/nodes/expressions/unary_operators/__pycache__/negative_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..45ad495 --- /dev/null +++ b/ql/ast/nodes/expressions/unary_operators/__pycache__/negative_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/unary_operators/__pycache__/unary_operator.cpython-35.pyc b/ql/ast/nodes/expressions/unary_operators/__pycache__/unary_operator.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..f72b4f0 --- /dev/null +++ b/ql/ast/nodes/expressions/unary_operators/__pycache__/unary_operator.cpython-35.pyc diff --git a/ql/ast/nodes/expressions/unary_operators/negation_operator.py b/ql/ast/nodes/expressions/unary_operators/negation_operator.py new file mode 100644 index 0000000..7b6b0c5 --- /dev/null +++ b/ql/ast/nodes/expressions/unary_operators/negation_operator.py @@ -0,0 +1,20 @@ +from ql.ast.nodes.expressions.unary_operators.unary_operator import UnaryOperatorNode +from ql.types.boolean import QLBoolean +from ql.types.undefined import QLUndefined + + +class NegationOperatorNode(UnaryOperatorNode): + def __init__(self, metadata, expression_type, expression, value): + super(NegationOperatorNode, self).__init__(metadata, expression_type, expression, value) + self.__valid_types = { + QLBoolean: QLBoolean, + } + + def get_result_type(self): + if self.__valid_types.get(self.expression.expression_type): + return self.__valid_types.get(self.expression.expression_type) + + return QLUndefined + + def evaluate(self): + self.value = QLBoolean(not self.expression.value) diff --git a/ql/ast/nodes/expressions/unary_operators/negative_operator.py b/ql/ast/nodes/expressions/unary_operators/negative_operator.py new file mode 100644 index 0000000..359ed2e --- /dev/null +++ b/ql/ast/nodes/expressions/unary_operators/negative_operator.py @@ -0,0 +1,23 @@ +from ql.ast.nodes.expressions.unary_operators.unary_operator import UnaryOperatorNode +from ql.types.decimal import QLDecimal +from ql.types.integer import QLInteger +from ql.types.money import QLMoney +from ql.types.undefined import QLUndefined + + +class NegativeOperatorNode(UnaryOperatorNode): + def __init__(self, metadata, expression_type, expression, value): + super(NegativeOperatorNode, self).__init__(metadata, expression_type, expression, value) + self.__valid_types = { + QLDecimal: QLDecimal, + QLInteger: QLInteger, + QLMoney: QLMoney} + + def get_result_type(self): + if self.__valid_types.get(self.expression.expression_type): + return self.__valid_types.get(self.expression.expression_type) + + return QLUndefined + + def evaluate(self): + self.value = -self.expression.value diff --git a/ql/ast/nodes/expressions/unary_operators/unary_operator.py b/ql/ast/nodes/expressions/unary_operators/unary_operator.py new file mode 100644 index 0000000..fa75249 --- /dev/null +++ b/ql/ast/nodes/expressions/unary_operators/unary_operator.py @@ -0,0 +1,11 @@ +from ql.ast.nodes.expressions.expression import ExpressionNode + + +class UnaryOperatorNode(ExpressionNode): + def __init__(self, metadata, expression_type, expression, value): + super(UnaryOperatorNode, self).__init__(metadata, expression_type, value) + self.__expression = expression + + @property + def expression(self): + return self.__expression diff --git a/ql/ast/nodes/expressions/variable.py b/ql/ast/nodes/expressions/variable.py new file mode 100644 index 0000000..c126372 --- /dev/null +++ b/ql/ast/nodes/expressions/variable.py @@ -0,0 +1,11 @@ +from ql.ast.nodes.expressions.expression import ExpressionNode + + +class VariableNode(ExpressionNode): + def __init__(self, metadata, expression_type, identifier, value): + super(VariableNode, self).__init__(metadata, expression_type, value) + self.__identifier = identifier + + @property + def identifier(self): + return self.__identifier diff --git a/ql/ast/nodes/statements/__pycache__/block_statement.cpython-35.pyc b/ql/ast/nodes/statements/__pycache__/block_statement.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..8ec170d --- /dev/null +++ b/ql/ast/nodes/statements/__pycache__/block_statement.cpython-35.pyc diff --git a/ql/ast/nodes/statements/__pycache__/form_statement.cpython-35.pyc b/ql/ast/nodes/statements/__pycache__/form_statement.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..e10775a --- /dev/null +++ b/ql/ast/nodes/statements/__pycache__/form_statement.cpython-35.pyc diff --git a/ql/ast/nodes/statements/__pycache__/if_statement.cpython-35.pyc b/ql/ast/nodes/statements/__pycache__/if_statement.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..e81cfc1 --- /dev/null +++ b/ql/ast/nodes/statements/__pycache__/if_statement.cpython-35.pyc diff --git a/ql/ast/nodes/statements/__pycache__/question_statement.cpython-35.pyc b/ql/ast/nodes/statements/__pycache__/question_statement.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..6b86ed9 --- /dev/null +++ b/ql/ast/nodes/statements/__pycache__/question_statement.cpython-35.pyc diff --git a/ql/ast/nodes/statements/block_statement.py b/ql/ast/nodes/statements/block_statement.py new file mode 100644 index 0000000..2013c82 --- /dev/null +++ b/ql/ast/nodes/statements/block_statement.py @@ -0,0 +1,11 @@ +from ql.ast.nodes.base import BaseNode + + +class BlockStatementNode(BaseNode): + def __init__(self, metadata, block): + super(BlockStatementNode, self).__init__(metadata) + self.__block = block + + @property + def block(self): + return self.__block diff --git a/ql/ast/nodes/statements/form_statement.py b/ql/ast/nodes/statements/form_statement.py new file mode 100644 index 0000000..0030623 --- /dev/null +++ b/ql/ast/nodes/statements/form_statement.py @@ -0,0 +1,12 @@ +from ql.ast.nodes.statements.block_statement import BlockStatementNode + + +class FormNode(BlockStatementNode): + def __init__(self, metadata, block, identifier): + super(FormNode, self).__init__(metadata, block) + self.__identifier = identifier + + @property + def identifier(self): + return self.__identifier + diff --git a/ql/ast/nodes/statements/if_statement.py b/ql/ast/nodes/statements/if_statement.py new file mode 100644 index 0000000..68845b8 --- /dev/null +++ b/ql/ast/nodes/statements/if_statement.py @@ -0,0 +1,11 @@ +from ql.ast.nodes.statements.block_statement import BlockStatementNode + + +class IfNode(BlockStatementNode): + def __init__(self, metadata, block, condition): + super(IfNode, self).__init__(metadata, block) + self.__condition = condition + + @property + def condition(self): + return self.__condition diff --git a/ql/ast/nodes/statements/question_statement.py b/ql/ast/nodes/statements/question_statement.py new file mode 100644 index 0000000..2878449 --- /dev/null +++ b/ql/ast/nodes/statements/question_statement.py @@ -0,0 +1,31 @@ +from ql.ast.nodes.base import BaseNode + + +class QuestionNode(BaseNode): + def __init__(self, line_number, label, identifier, answer_type, answer, computed): + super(QuestionNode, self).__init__(line_number) + self.__label = label + self.__identifier = identifier + self.__answer_type = answer_type + self.__answer = answer + self.__computed = computed + + @property + def label(self): + return self.__label + + @property + def identifier(self): + return self.__identifier + + @property + def answer_type(self): + return self.__answer_type + + @property + def answer(self): + return self.__answer + + @property + def computed(self): + return self.__computed 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 diff --git a/ql/parser/__pycache__/lexer.cpython-35.pyc b/ql/parser/__pycache__/lexer.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..f2d9220 --- /dev/null +++ b/ql/parser/__pycache__/lexer.cpython-35.pyc diff --git a/ql/parser/__pycache__/metadata.cpython-35.pyc b/ql/parser/__pycache__/metadata.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..0f1f298 --- /dev/null +++ b/ql/parser/__pycache__/metadata.cpython-35.pyc diff --git a/ql/parser/__pycache__/parser.cpython-35.pyc b/ql/parser/__pycache__/parser.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..6eb96b9 --- /dev/null +++ b/ql/parser/__pycache__/parser.cpython-35.pyc diff --git a/ql/parser/__pycache__/parsetab.cpython-35.pyc b/ql/parser/__pycache__/parsetab.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..bd4db77 --- /dev/null +++ b/ql/parser/__pycache__/parsetab.cpython-35.pyc diff --git a/ql/parser/lexer.py b/ql/parser/lexer.py new file mode 100644 index 0000000..6e53f12 --- /dev/null +++ b/ql/parser/lexer.py @@ -0,0 +1,153 @@ +from re import findall
+
+from ply.lex import lex
+
+
+class QLLexer:
+ def __init__(self):
+ self.__errors = []
+ self.__lexer = None
+
+ @property
+ def lexer(self):
+ return self.__lexer
+
+ @property
+ def errors(self):
+ return self.__errors
+
+ def build(self):
+ self.__lexer = lex(module=self)
+
+ def tokenize(self, data):
+ self.__errors = []
+ self.lexer.input(data)
+ token = self.lexer.token()
+ tokens = [token]
+
+ while token:
+ token = self.lexer.token()
+ tokens.append(token)
+
+ return tokens
+
+ tokens = [
+ 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'COLON',
+ 'ASSIGN',
+ 'EQUALS', 'NOT_EQUALS',
+ 'LESS_EQUALS', 'LESS_THAN', 'GREATER_EQUALS', 'GREATER_THAN',
+ 'AND', 'OR',
+ 'DOLLAR', 'RUBLE',
+ 'LEFT_BRACE', 'RIGHT_BRACE',
+ 'LEFT_BRACKET', 'RIGHT_BRACKET',
+ 'INTEGER_LITERAL', 'DECIMAL_LITERAL',
+ 'TRUE', 'FALSE',
+ 'DATE_LITERAL',
+ 'STRING_LITERAL',
+ 'IDENTIFIER',
+ ]
+
+ reserved_keywords = {
+ 'form': 'FORM',
+ 'if': 'IF',
+ 'not': 'NOT',
+
+ # Types
+ 'boolean': 'BOOLEAN',
+ 'date': 'DATE',
+ 'decimal': 'DECIMAL',
+ 'integer': 'INTEGER',
+ 'money': 'MONEY',
+ 'string': 'STRING',
+ }
+
+ tokens += list(reserved_keywords.values())
+
+ # Regular expression rules for simple tokens
+ t_ignore = ' \t'
+
+ t_PLUS = r'\+'
+ t_MINUS = r'-'
+ t_TIMES = r'\*'
+ t_DIVIDE = r'/'
+ t_COLON = r':'
+ t_ASSIGN = r'='
+
+ t_LESS_EQUALS = r'<='
+ t_LESS_THAN = r'<'
+ t_GREATER_EQUALS = r'>='
+ t_GREATER_THAN = r'>'
+ t_EQUALS = r'=='
+ t_NOT_EQUALS = r'!='
+ t_AND = r'&&'
+ t_OR = r'\|\|'
+
+ t_DOLLAR = r'\$'
+ t_RUBLE = r'\₽'
+
+ t_LEFT_BRACE = r'\{'
+ t_RIGHT_BRACE = r'\}'
+
+ t_LEFT_BRACKET = r'\('
+ t_RIGHT_BRACKET = r'\)'
+
+ # Literals
+ @staticmethod
+ def t_FALSE(token):
+ r'False'
+ token.value = False
+ return token
+
+ @staticmethod
+ def t_TRUE(token):
+ r'True'
+ token.value = True
+ return token
+
+ def t_DATE_LITERAL(self, token):
+ r'date\(\s*\d{1,2}\s*,\s*\d{1,2}\s*,\s*\d{1,4}\s*\)'
+
+ try:
+ token.value = findall(r'\d\d*', token.value)
+ return token
+ except SyntaxError:
+ self.errors.append('Invalid date.')
+
+ @staticmethod
+ def t_DECIMAL_LITERAL(token):
+ r'\d+[.]\d+'
+ token.value = token.value
+ return token
+
+ @staticmethod
+ def t_INTEGER_LITERAL(token):
+ r'\d+'
+ token.value = token.value
+ return token
+
+ @staticmethod
+ def t_STRING_LITERAL(token):
+ r'\"(.+?)\"'
+ token.value = token.value[1:-1]
+ return token
+
+ # Other
+ def t_IDENTIFIER(self, token):
+ r'[a-z][a-zA-Z_0-9]*'
+ token.type = self.reserved_keywords.get(token.value, 'IDENTIFIER')
+ return token
+
+ @staticmethod
+ def t_comment(token):
+ r'//.*'
+ pass
+
+ @staticmethod
+ def t_newline(token):
+ r'\n+'
+ token.lexer.lineno += len(token.value)
+
+ # Error handling
+ def t_error(self, token):
+ self.errors.append("Illegal character '%s'" % token.value[0])
+ token.lexer.skip(1)
diff --git a/ql/parser/metadata.py b/ql/parser/metadata.py new file mode 100644 index 0000000..618b4ba --- /dev/null +++ b/ql/parser/metadata.py @@ -0,0 +1,7 @@ +class Metadata: + def __init__(self, line): + self.__line = line + + @property + def line(self): + return self.__line diff --git a/ql/parser/parser.out b/ql/parser/parser.out new file mode 100644 index 0000000..e1a1452 --- /dev/null +++ b/ql/parser/parser.out @@ -0,0 +1,2214 @@ +Created by PLY version 3.11 (http://www.dabeaz.com/ply) + +Grammar + +Rule 0 S' -> form +Rule 1 form -> FORM IDENTIFIER block +Rule 2 block -> LEFT_BRACE statements RIGHT_BRACE +Rule 3 statements -> statement statements +Rule 4 statements -> statement +Rule 5 statement -> if +Rule 6 statement -> question +Rule 7 question -> STRING_LITERAL IDENTIFIER COLON type +Rule 8 question -> STRING_LITERAL IDENTIFIER COLON type ASSIGN expression +Rule 9 if -> IF condition block +Rule 10 condition -> LEFT_BRACKET expression RIGHT_BRACKET +Rule 11 expression -> LEFT_BRACKET expression RIGHT_BRACKET +Rule 12 expression -> IDENTIFIER +Rule 13 expression -> NOT expression +Rule 14 expression -> MINUS expression +Rule 15 expression -> expression AND expression +Rule 16 expression -> expression OR expression +Rule 17 expression -> expression PLUS expression +Rule 18 expression -> expression MINUS expression +Rule 19 expression -> expression TIMES expression +Rule 20 expression -> expression DIVIDE expression +Rule 21 expression -> expression EQUALS expression +Rule 22 expression -> expression NOT_EQUALS expression +Rule 23 expression -> expression LESS_EQUALS expression +Rule 24 expression -> expression LESS_THAN expression +Rule 25 expression -> expression GREATER_EQUALS expression +Rule 26 expression -> expression GREATER_THAN expression +Rule 27 expression -> FALSE +Rule 28 expression -> TRUE +Rule 29 expression -> DATE_LITERAL +Rule 30 expression -> INTEGER_LITERAL +Rule 31 expression -> DECIMAL_LITERAL +Rule 32 expression -> currency DECIMAL_LITERAL +Rule 33 expression -> currency INTEGER_LITERAL +Rule 34 expression -> STRING_LITERAL +Rule 35 currency -> DOLLAR +Rule 36 currency -> RUBLE +Rule 37 type -> BOOLEAN +Rule 38 type -> DECIMAL +Rule 39 type -> STRING +Rule 40 type -> DATE +Rule 41 type -> MONEY +Rule 42 type -> INTEGER +Rule 43 form -> FORM LEFT_BRACE +Rule 44 form -> FORM IDENTIFIER LEFT_BRACE RIGHT_BRACE +Rule 45 statement -> IF condition LEFT_BRACE RIGHT_BRACE +Rule 46 condition -> LEFT_BRACKET RIGHT_BRACKET + +Terminals, with rules where they appear + +AND : 15 +ASSIGN : 8 +BOOLEAN : 37 +COLON : 7 8 +DATE : 40 +DATE_LITERAL : 29 +DECIMAL : 38 +DECIMAL_LITERAL : 31 32 +DIVIDE : 20 +DOLLAR : 35 +EQUALS : 21 +FALSE : 27 +FORM : 1 43 44 +GREATER_EQUALS : 25 +GREATER_THAN : 26 +IDENTIFIER : 1 7 8 12 44 +IF : 9 45 +INTEGER : 42 +INTEGER_LITERAL : 30 33 +LEFT_BRACE : 2 43 44 45 +LEFT_BRACKET : 10 11 46 +LESS_EQUALS : 23 +LESS_THAN : 24 +MINUS : 14 18 +MONEY : 41 +NOT : 13 +NOT_EQUALS : 22 +OR : 16 +PLUS : 17 +RIGHT_BRACE : 2 44 45 +RIGHT_BRACKET : 10 11 46 +RUBLE : 36 +STRING : 39 +STRING_LITERAL : 7 8 34 +TIMES : 19 +TRUE : 28 +error : + +Nonterminals, with rules where they appear + +block : 1 9 +condition : 9 45 +currency : 32 33 +expression : 8 10 11 13 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 24 24 25 25 26 26 +form : 0 +if : 5 +question : 6 +statement : 3 4 +statements : 2 3 +type : 7 8 + +Parsing method: LALR + +state 0 + + (0) S' -> . form + (1) form -> . FORM IDENTIFIER block + (43) form -> . FORM LEFT_BRACE + (44) form -> . FORM IDENTIFIER LEFT_BRACE RIGHT_BRACE + + FORM shift and go to state 1 + + form shift and go to state 2 + +state 1 + + (1) form -> FORM . IDENTIFIER block + (43) form -> FORM . LEFT_BRACE + (44) form -> FORM . IDENTIFIER LEFT_BRACE RIGHT_BRACE + + IDENTIFIER shift and go to state 3 + LEFT_BRACE shift and go to state 4 + + +state 2 + + (0) S' -> form . + + + +state 3 + + (1) form -> FORM IDENTIFIER . block + (44) form -> FORM IDENTIFIER . LEFT_BRACE RIGHT_BRACE + (2) block -> . LEFT_BRACE statements RIGHT_BRACE + + LEFT_BRACE shift and go to state 5 + + block shift and go to state 6 + +state 4 + + (43) form -> FORM LEFT_BRACE . + + $end reduce using rule 43 (form -> FORM LEFT_BRACE .) + + +state 5 + + (44) form -> FORM IDENTIFIER LEFT_BRACE . RIGHT_BRACE + (2) block -> LEFT_BRACE . statements RIGHT_BRACE + (3) statements -> . statement statements + (4) statements -> . statement + (5) statement -> . if + (6) statement -> . question + (45) statement -> . IF condition LEFT_BRACE RIGHT_BRACE + (9) if -> . IF condition block + (7) question -> . STRING_LITERAL IDENTIFIER COLON type + (8) question -> . STRING_LITERAL IDENTIFIER COLON type ASSIGN expression + + RIGHT_BRACE shift and go to state 13 + IF shift and go to state 11 + STRING_LITERAL shift and go to state 12 + + if shift and go to state 7 + question shift and go to state 8 + statements shift and go to state 9 + statement shift and go to state 10 + +state 6 + + (1) form -> FORM IDENTIFIER block . + + $end reduce using rule 1 (form -> FORM IDENTIFIER block .) + + +state 7 + + (5) statement -> if . + + IF reduce using rule 5 (statement -> if .) + STRING_LITERAL reduce using rule 5 (statement -> if .) + RIGHT_BRACE reduce using rule 5 (statement -> if .) + + +state 8 + + (6) statement -> question . + + IF reduce using rule 6 (statement -> question .) + STRING_LITERAL reduce using rule 6 (statement -> question .) + RIGHT_BRACE reduce using rule 6 (statement -> question .) + + +state 9 + + (2) block -> LEFT_BRACE statements . RIGHT_BRACE + + RIGHT_BRACE shift and go to state 14 + + +state 10 + + (3) statements -> statement . statements + (4) statements -> statement . + (3) statements -> . statement statements + (4) statements -> . statement + (5) statement -> . if + (6) statement -> . question + (45) statement -> . IF condition LEFT_BRACE RIGHT_BRACE + (9) if -> . IF condition block + (7) question -> . STRING_LITERAL IDENTIFIER COLON type + (8) question -> . STRING_LITERAL IDENTIFIER COLON type ASSIGN expression + + RIGHT_BRACE reduce using rule 4 (statements -> statement .) + IF shift and go to state 11 + STRING_LITERAL shift and go to state 12 + + if shift and go to state 7 + question shift and go to state 8 + statements shift and go to state 15 + statement shift and go to state 10 + +state 11 + + (45) statement -> IF . condition LEFT_BRACE RIGHT_BRACE + (9) if -> IF . condition block + (10) condition -> . LEFT_BRACKET expression RIGHT_BRACKET + (46) condition -> . LEFT_BRACKET RIGHT_BRACKET + + LEFT_BRACKET shift and go to state 17 + + condition shift and go to state 16 + +state 12 + + (7) question -> STRING_LITERAL . IDENTIFIER COLON type + (8) question -> STRING_LITERAL . IDENTIFIER COLON type ASSIGN expression + + IDENTIFIER shift and go to state 18 + + +state 13 + + (44) form -> FORM IDENTIFIER LEFT_BRACE RIGHT_BRACE . + + $end reduce using rule 44 (form -> FORM IDENTIFIER LEFT_BRACE RIGHT_BRACE .) + + +state 14 + + (2) block -> LEFT_BRACE statements RIGHT_BRACE . + + IF reduce using rule 2 (block -> LEFT_BRACE statements RIGHT_BRACE .) + STRING_LITERAL reduce using rule 2 (block -> LEFT_BRACE statements RIGHT_BRACE .) + RIGHT_BRACE reduce using rule 2 (block -> LEFT_BRACE statements RIGHT_BRACE .) + $end reduce using rule 2 (block -> LEFT_BRACE statements RIGHT_BRACE .) + + +state 15 + + (3) statements -> statement statements . + + RIGHT_BRACE reduce using rule 3 (statements -> statement statements .) + + +state 16 + + (45) statement -> IF condition . LEFT_BRACE RIGHT_BRACE + (9) if -> IF condition . block + (2) block -> . LEFT_BRACE statements RIGHT_BRACE + + LEFT_BRACE shift and go to state 19 + + block shift and go to state 20 + +state 17 + + (10) condition -> LEFT_BRACKET . expression RIGHT_BRACKET + (46) condition -> LEFT_BRACKET . RIGHT_BRACKET + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + RIGHT_BRACKET shift and go to state 21 + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 33 + +state 18 + + (7) question -> STRING_LITERAL IDENTIFIER . COLON type + (8) question -> STRING_LITERAL IDENTIFIER . COLON type ASSIGN expression + + COLON shift and go to state 36 + + +state 19 + + (45) statement -> IF condition LEFT_BRACE . RIGHT_BRACE + (2) block -> LEFT_BRACE . statements RIGHT_BRACE + (3) statements -> . statement statements + (4) statements -> . statement + (5) statement -> . if + (6) statement -> . question + (45) statement -> . IF condition LEFT_BRACE RIGHT_BRACE + (9) if -> . IF condition block + (7) question -> . STRING_LITERAL IDENTIFIER COLON type + (8) question -> . STRING_LITERAL IDENTIFIER COLON type ASSIGN expression + + RIGHT_BRACE shift and go to state 37 + IF shift and go to state 11 + STRING_LITERAL shift and go to state 12 + + if shift and go to state 7 + question shift and go to state 8 + statements shift and go to state 9 + statement shift and go to state 10 + +state 20 + + (9) if -> IF condition block . + + IF reduce using rule 9 (if -> IF condition block .) + STRING_LITERAL reduce using rule 9 (if -> IF condition block .) + RIGHT_BRACE reduce using rule 9 (if -> IF condition block .) + + +state 21 + + (46) condition -> LEFT_BRACKET RIGHT_BRACKET . + + LEFT_BRACE reduce using rule 46 (condition -> LEFT_BRACKET RIGHT_BRACKET .) + + +state 22 + + (32) expression -> currency . DECIMAL_LITERAL + (33) expression -> currency . INTEGER_LITERAL + + DECIMAL_LITERAL shift and go to state 38 + INTEGER_LITERAL shift and go to state 39 + + +state 23 + + (36) currency -> RUBLE . + + DECIMAL_LITERAL reduce using rule 36 (currency -> RUBLE .) + INTEGER_LITERAL reduce using rule 36 (currency -> RUBLE .) + + +state 24 + + (29) expression -> DATE_LITERAL . + + AND reduce using rule 29 (expression -> DATE_LITERAL .) + OR reduce using rule 29 (expression -> DATE_LITERAL .) + PLUS reduce using rule 29 (expression -> DATE_LITERAL .) + MINUS reduce using rule 29 (expression -> DATE_LITERAL .) + TIMES reduce using rule 29 (expression -> DATE_LITERAL .) + DIVIDE reduce using rule 29 (expression -> DATE_LITERAL .) + EQUALS reduce using rule 29 (expression -> DATE_LITERAL .) + NOT_EQUALS reduce using rule 29 (expression -> DATE_LITERAL .) + LESS_EQUALS reduce using rule 29 (expression -> DATE_LITERAL .) + LESS_THAN reduce using rule 29 (expression -> DATE_LITERAL .) + GREATER_EQUALS reduce using rule 29 (expression -> DATE_LITERAL .) + GREATER_THAN reduce using rule 29 (expression -> DATE_LITERAL .) + IF reduce using rule 29 (expression -> DATE_LITERAL .) + STRING_LITERAL reduce using rule 29 (expression -> DATE_LITERAL .) + RIGHT_BRACE reduce using rule 29 (expression -> DATE_LITERAL .) + RIGHT_BRACKET reduce using rule 29 (expression -> DATE_LITERAL .) + + +state 25 + + (14) expression -> MINUS . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 40 + +state 26 + + (30) expression -> INTEGER_LITERAL . + + AND reduce using rule 30 (expression -> INTEGER_LITERAL .) + OR reduce using rule 30 (expression -> INTEGER_LITERAL .) + PLUS reduce using rule 30 (expression -> INTEGER_LITERAL .) + MINUS reduce using rule 30 (expression -> INTEGER_LITERAL .) + TIMES reduce using rule 30 (expression -> INTEGER_LITERAL .) + DIVIDE reduce using rule 30 (expression -> INTEGER_LITERAL .) + EQUALS reduce using rule 30 (expression -> INTEGER_LITERAL .) + NOT_EQUALS reduce using rule 30 (expression -> INTEGER_LITERAL .) + LESS_EQUALS reduce using rule 30 (expression -> INTEGER_LITERAL .) + LESS_THAN reduce using rule 30 (expression -> INTEGER_LITERAL .) + GREATER_EQUALS reduce using rule 30 (expression -> INTEGER_LITERAL .) + GREATER_THAN reduce using rule 30 (expression -> INTEGER_LITERAL .) + IF reduce using rule 30 (expression -> INTEGER_LITERAL .) + STRING_LITERAL reduce using rule 30 (expression -> INTEGER_LITERAL .) + RIGHT_BRACE reduce using rule 30 (expression -> INTEGER_LITERAL .) + RIGHT_BRACKET reduce using rule 30 (expression -> INTEGER_LITERAL .) + + +state 27 + + (13) expression -> NOT . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 41 + +state 28 + + (34) expression -> STRING_LITERAL . + + AND reduce using rule 34 (expression -> STRING_LITERAL .) + OR reduce using rule 34 (expression -> STRING_LITERAL .) + PLUS reduce using rule 34 (expression -> STRING_LITERAL .) + MINUS reduce using rule 34 (expression -> STRING_LITERAL .) + TIMES reduce using rule 34 (expression -> STRING_LITERAL .) + DIVIDE reduce using rule 34 (expression -> STRING_LITERAL .) + EQUALS reduce using rule 34 (expression -> STRING_LITERAL .) + NOT_EQUALS reduce using rule 34 (expression -> STRING_LITERAL .) + LESS_EQUALS reduce using rule 34 (expression -> STRING_LITERAL .) + LESS_THAN reduce using rule 34 (expression -> STRING_LITERAL .) + GREATER_EQUALS reduce using rule 34 (expression -> STRING_LITERAL .) + GREATER_THAN reduce using rule 34 (expression -> STRING_LITERAL .) + IF reduce using rule 34 (expression -> STRING_LITERAL .) + STRING_LITERAL reduce using rule 34 (expression -> STRING_LITERAL .) + RIGHT_BRACE reduce using rule 34 (expression -> STRING_LITERAL .) + RIGHT_BRACKET reduce using rule 34 (expression -> STRING_LITERAL .) + + +state 29 + + (35) currency -> DOLLAR . + + DECIMAL_LITERAL reduce using rule 35 (currency -> DOLLAR .) + INTEGER_LITERAL reduce using rule 35 (currency -> DOLLAR .) + + +state 30 + + (11) expression -> LEFT_BRACKET . expression RIGHT_BRACKET + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 42 + +state 31 + + (31) expression -> DECIMAL_LITERAL . + + AND reduce using rule 31 (expression -> DECIMAL_LITERAL .) + OR reduce using rule 31 (expression -> DECIMAL_LITERAL .) + PLUS reduce using rule 31 (expression -> DECIMAL_LITERAL .) + MINUS reduce using rule 31 (expression -> DECIMAL_LITERAL .) + TIMES reduce using rule 31 (expression -> DECIMAL_LITERAL .) + DIVIDE reduce using rule 31 (expression -> DECIMAL_LITERAL .) + EQUALS reduce using rule 31 (expression -> DECIMAL_LITERAL .) + NOT_EQUALS reduce using rule 31 (expression -> DECIMAL_LITERAL .) + LESS_EQUALS reduce using rule 31 (expression -> DECIMAL_LITERAL .) + LESS_THAN reduce using rule 31 (expression -> DECIMAL_LITERAL .) + GREATER_EQUALS reduce using rule 31 (expression -> DECIMAL_LITERAL .) + GREATER_THAN reduce using rule 31 (expression -> DECIMAL_LITERAL .) + IF reduce using rule 31 (expression -> DECIMAL_LITERAL .) + STRING_LITERAL reduce using rule 31 (expression -> DECIMAL_LITERAL .) + RIGHT_BRACE reduce using rule 31 (expression -> DECIMAL_LITERAL .) + RIGHT_BRACKET reduce using rule 31 (expression -> DECIMAL_LITERAL .) + + +state 32 + + (28) expression -> TRUE . + + AND reduce using rule 28 (expression -> TRUE .) + OR reduce using rule 28 (expression -> TRUE .) + PLUS reduce using rule 28 (expression -> TRUE .) + MINUS reduce using rule 28 (expression -> TRUE .) + TIMES reduce using rule 28 (expression -> TRUE .) + DIVIDE reduce using rule 28 (expression -> TRUE .) + EQUALS reduce using rule 28 (expression -> TRUE .) + NOT_EQUALS reduce using rule 28 (expression -> TRUE .) + LESS_EQUALS reduce using rule 28 (expression -> TRUE .) + LESS_THAN reduce using rule 28 (expression -> TRUE .) + GREATER_EQUALS reduce using rule 28 (expression -> TRUE .) + GREATER_THAN reduce using rule 28 (expression -> TRUE .) + IF reduce using rule 28 (expression -> TRUE .) + STRING_LITERAL reduce using rule 28 (expression -> TRUE .) + RIGHT_BRACE reduce using rule 28 (expression -> TRUE .) + RIGHT_BRACKET reduce using rule 28 (expression -> TRUE .) + + +state 33 + + (10) condition -> LEFT_BRACKET expression . RIGHT_BRACKET + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + RIGHT_BRACKET shift and go to state 43 + AND shift and go to state 52 + OR shift and go to state 50 + PLUS shift and go to state 44 + MINUS shift and go to state 48 + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + EQUALS shift and go to state 46 + NOT_EQUALS shift and go to state 45 + LESS_EQUALS shift and go to state 54 + LESS_THAN shift and go to state 47 + GREATER_EQUALS shift and go to state 55 + GREATER_THAN shift and go to state 53 + + +state 34 + + (12) expression -> IDENTIFIER . + + AND reduce using rule 12 (expression -> IDENTIFIER .) + OR reduce using rule 12 (expression -> IDENTIFIER .) + PLUS reduce using rule 12 (expression -> IDENTIFIER .) + MINUS reduce using rule 12 (expression -> IDENTIFIER .) + TIMES reduce using rule 12 (expression -> IDENTIFIER .) + DIVIDE reduce using rule 12 (expression -> IDENTIFIER .) + EQUALS reduce using rule 12 (expression -> IDENTIFIER .) + NOT_EQUALS reduce using rule 12 (expression -> IDENTIFIER .) + LESS_EQUALS reduce using rule 12 (expression -> IDENTIFIER .) + LESS_THAN reduce using rule 12 (expression -> IDENTIFIER .) + GREATER_EQUALS reduce using rule 12 (expression -> IDENTIFIER .) + GREATER_THAN reduce using rule 12 (expression -> IDENTIFIER .) + IF reduce using rule 12 (expression -> IDENTIFIER .) + STRING_LITERAL reduce using rule 12 (expression -> IDENTIFIER .) + RIGHT_BRACE reduce using rule 12 (expression -> IDENTIFIER .) + RIGHT_BRACKET reduce using rule 12 (expression -> IDENTIFIER .) + + +state 35 + + (27) expression -> FALSE . + + AND reduce using rule 27 (expression -> FALSE .) + OR reduce using rule 27 (expression -> FALSE .) + PLUS reduce using rule 27 (expression -> FALSE .) + MINUS reduce using rule 27 (expression -> FALSE .) + TIMES reduce using rule 27 (expression -> FALSE .) + DIVIDE reduce using rule 27 (expression -> FALSE .) + EQUALS reduce using rule 27 (expression -> FALSE .) + NOT_EQUALS reduce using rule 27 (expression -> FALSE .) + LESS_EQUALS reduce using rule 27 (expression -> FALSE .) + LESS_THAN reduce using rule 27 (expression -> FALSE .) + GREATER_EQUALS reduce using rule 27 (expression -> FALSE .) + GREATER_THAN reduce using rule 27 (expression -> FALSE .) + IF reduce using rule 27 (expression -> FALSE .) + STRING_LITERAL reduce using rule 27 (expression -> FALSE .) + RIGHT_BRACE reduce using rule 27 (expression -> FALSE .) + RIGHT_BRACKET reduce using rule 27 (expression -> FALSE .) + + +state 36 + + (7) question -> STRING_LITERAL IDENTIFIER COLON . type + (8) question -> STRING_LITERAL IDENTIFIER COLON . type ASSIGN expression + (37) type -> . BOOLEAN + (38) type -> . DECIMAL + (39) type -> . STRING + (40) type -> . DATE + (41) type -> . MONEY + (42) type -> . INTEGER + + BOOLEAN shift and go to state 62 + DECIMAL shift and go to state 57 + STRING shift and go to state 58 + DATE shift and go to state 56 + MONEY shift and go to state 60 + INTEGER shift and go to state 61 + + type shift and go to state 59 + +state 37 + + (45) statement -> IF condition LEFT_BRACE RIGHT_BRACE . + + IF reduce using rule 45 (statement -> IF condition LEFT_BRACE RIGHT_BRACE .) + STRING_LITERAL reduce using rule 45 (statement -> IF condition LEFT_BRACE RIGHT_BRACE .) + RIGHT_BRACE reduce using rule 45 (statement -> IF condition LEFT_BRACE RIGHT_BRACE .) + + +state 38 + + (32) expression -> currency DECIMAL_LITERAL . + + AND reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + OR reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + PLUS reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + MINUS reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + TIMES reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + DIVIDE reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + EQUALS reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + NOT_EQUALS reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + LESS_EQUALS reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + LESS_THAN reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + GREATER_EQUALS reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + GREATER_THAN reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + IF reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + STRING_LITERAL reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + RIGHT_BRACE reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + RIGHT_BRACKET reduce using rule 32 (expression -> currency DECIMAL_LITERAL .) + + +state 39 + + (33) expression -> currency INTEGER_LITERAL . + + AND reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + OR reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + PLUS reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + MINUS reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + TIMES reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + DIVIDE reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + EQUALS reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + NOT_EQUALS reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + LESS_EQUALS reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + LESS_THAN reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + GREATER_EQUALS reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + GREATER_THAN reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + IF reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + STRING_LITERAL reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + RIGHT_BRACE reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + RIGHT_BRACKET reduce using rule 33 (expression -> currency INTEGER_LITERAL .) + + +state 40 + + (14) expression -> MINUS expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 14 (expression -> MINUS expression .) + OR reduce using rule 14 (expression -> MINUS expression .) + PLUS reduce using rule 14 (expression -> MINUS expression .) + MINUS reduce using rule 14 (expression -> MINUS expression .) + EQUALS reduce using rule 14 (expression -> MINUS expression .) + NOT_EQUALS reduce using rule 14 (expression -> MINUS expression .) + LESS_EQUALS reduce using rule 14 (expression -> MINUS expression .) + LESS_THAN reduce using rule 14 (expression -> MINUS expression .) + GREATER_EQUALS reduce using rule 14 (expression -> MINUS expression .) + GREATER_THAN reduce using rule 14 (expression -> MINUS expression .) + IF reduce using rule 14 (expression -> MINUS expression .) + STRING_LITERAL reduce using rule 14 (expression -> MINUS expression .) + RIGHT_BRACE reduce using rule 14 (expression -> MINUS expression .) + RIGHT_BRACKET reduce using rule 14 (expression -> MINUS expression .) + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + + ! TIMES [ reduce using rule 14 (expression -> MINUS expression .) ] + ! DIVIDE [ reduce using rule 14 (expression -> MINUS expression .) ] + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + ! PLUS [ shift and go to state 44 ] + ! MINUS [ shift and go to state 48 ] + ! EQUALS [ shift and go to state 46 ] + ! NOT_EQUALS [ shift and go to state 45 ] + ! LESS_EQUALS [ shift and go to state 54 ] + ! LESS_THAN [ shift and go to state 47 ] + ! GREATER_EQUALS [ shift and go to state 55 ] + ! GREATER_THAN [ shift and go to state 53 ] + + +state 41 + + (13) expression -> NOT expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 13 (expression -> NOT expression .) + OR reduce using rule 13 (expression -> NOT expression .) + PLUS reduce using rule 13 (expression -> NOT expression .) + MINUS reduce using rule 13 (expression -> NOT expression .) + TIMES reduce using rule 13 (expression -> NOT expression .) + DIVIDE reduce using rule 13 (expression -> NOT expression .) + EQUALS reduce using rule 13 (expression -> NOT expression .) + NOT_EQUALS reduce using rule 13 (expression -> NOT expression .) + LESS_EQUALS reduce using rule 13 (expression -> NOT expression .) + LESS_THAN reduce using rule 13 (expression -> NOT expression .) + GREATER_EQUALS reduce using rule 13 (expression -> NOT expression .) + GREATER_THAN reduce using rule 13 (expression -> NOT expression .) + IF reduce using rule 13 (expression -> NOT expression .) + STRING_LITERAL reduce using rule 13 (expression -> NOT expression .) + RIGHT_BRACE reduce using rule 13 (expression -> NOT expression .) + RIGHT_BRACKET reduce using rule 13 (expression -> NOT expression .) + + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + ! PLUS [ shift and go to state 44 ] + ! MINUS [ shift and go to state 48 ] + ! TIMES [ shift and go to state 49 ] + ! DIVIDE [ shift and go to state 51 ] + ! EQUALS [ shift and go to state 46 ] + ! NOT_EQUALS [ shift and go to state 45 ] + ! LESS_EQUALS [ shift and go to state 54 ] + ! LESS_THAN [ shift and go to state 47 ] + ! GREATER_EQUALS [ shift and go to state 55 ] + ! GREATER_THAN [ shift and go to state 53 ] + + +state 42 + + (11) expression -> LEFT_BRACKET expression . RIGHT_BRACKET + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + RIGHT_BRACKET shift and go to state 63 + AND shift and go to state 52 + OR shift and go to state 50 + PLUS shift and go to state 44 + MINUS shift and go to state 48 + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + EQUALS shift and go to state 46 + NOT_EQUALS shift and go to state 45 + LESS_EQUALS shift and go to state 54 + LESS_THAN shift and go to state 47 + GREATER_EQUALS shift and go to state 55 + GREATER_THAN shift and go to state 53 + + +state 43 + + (10) condition -> LEFT_BRACKET expression RIGHT_BRACKET . + + LEFT_BRACE reduce using rule 10 (condition -> LEFT_BRACKET expression RIGHT_BRACKET .) + + +state 44 + + (17) expression -> expression PLUS . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 64 + +state 45 + + (22) expression -> expression NOT_EQUALS . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 65 + +state 46 + + (21) expression -> expression EQUALS . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 66 + +state 47 + + (24) expression -> expression LESS_THAN . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 67 + +state 48 + + (18) expression -> expression MINUS . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 68 + +state 49 + + (19) expression -> expression TIMES . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 69 + +state 50 + + (16) expression -> expression OR . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 70 + +state 51 + + (20) expression -> expression DIVIDE . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 71 + +state 52 + + (15) expression -> expression AND . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 72 + +state 53 + + (26) expression -> expression GREATER_THAN . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 73 + +state 54 + + (23) expression -> expression LESS_EQUALS . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 74 + +state 55 + + (25) expression -> expression GREATER_EQUALS . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + currency shift and go to state 22 + expression shift and go to state 75 + +state 56 + + (40) type -> DATE . + + ASSIGN reduce using rule 40 (type -> DATE .) + IF reduce using rule 40 (type -> DATE .) + STRING_LITERAL reduce using rule 40 (type -> DATE .) + RIGHT_BRACE reduce using rule 40 (type -> DATE .) + + +state 57 + + (38) type -> DECIMAL . + + ASSIGN reduce using rule 38 (type -> DECIMAL .) + IF reduce using rule 38 (type -> DECIMAL .) + STRING_LITERAL reduce using rule 38 (type -> DECIMAL .) + RIGHT_BRACE reduce using rule 38 (type -> DECIMAL .) + + +state 58 + + (39) type -> STRING . + + ASSIGN reduce using rule 39 (type -> STRING .) + IF reduce using rule 39 (type -> STRING .) + STRING_LITERAL reduce using rule 39 (type -> STRING .) + RIGHT_BRACE reduce using rule 39 (type -> STRING .) + + +state 59 + + (7) question -> STRING_LITERAL IDENTIFIER COLON type . + (8) question -> STRING_LITERAL IDENTIFIER COLON type . ASSIGN expression + + IF reduce using rule 7 (question -> STRING_LITERAL IDENTIFIER COLON type .) + STRING_LITERAL reduce using rule 7 (question -> STRING_LITERAL IDENTIFIER COLON type .) + RIGHT_BRACE reduce using rule 7 (question -> STRING_LITERAL IDENTIFIER COLON type .) + ASSIGN shift and go to state 76 + + +state 60 + + (41) type -> MONEY . + + ASSIGN reduce using rule 41 (type -> MONEY .) + IF reduce using rule 41 (type -> MONEY .) + STRING_LITERAL reduce using rule 41 (type -> MONEY .) + RIGHT_BRACE reduce using rule 41 (type -> MONEY .) + + +state 61 + + (42) type -> INTEGER . + + ASSIGN reduce using rule 42 (type -> INTEGER .) + IF reduce using rule 42 (type -> INTEGER .) + STRING_LITERAL reduce using rule 42 (type -> INTEGER .) + RIGHT_BRACE reduce using rule 42 (type -> INTEGER .) + + +state 62 + + (37) type -> BOOLEAN . + + ASSIGN reduce using rule 37 (type -> BOOLEAN .) + IF reduce using rule 37 (type -> BOOLEAN .) + STRING_LITERAL reduce using rule 37 (type -> BOOLEAN .) + RIGHT_BRACE reduce using rule 37 (type -> BOOLEAN .) + + +state 63 + + (11) expression -> LEFT_BRACKET expression RIGHT_BRACKET . + + AND reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + OR reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + PLUS reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + MINUS reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + TIMES reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + DIVIDE reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + EQUALS reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + NOT_EQUALS reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + LESS_EQUALS reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + LESS_THAN reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + GREATER_EQUALS reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + GREATER_THAN reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + IF reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + STRING_LITERAL reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + RIGHT_BRACE reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + RIGHT_BRACKET reduce using rule 11 (expression -> LEFT_BRACKET expression RIGHT_BRACKET .) + + +state 64 + + (17) expression -> expression PLUS expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 17 (expression -> expression PLUS expression .) + OR reduce using rule 17 (expression -> expression PLUS expression .) + PLUS reduce using rule 17 (expression -> expression PLUS expression .) + MINUS reduce using rule 17 (expression -> expression PLUS expression .) + EQUALS reduce using rule 17 (expression -> expression PLUS expression .) + NOT_EQUALS reduce using rule 17 (expression -> expression PLUS expression .) + LESS_EQUALS reduce using rule 17 (expression -> expression PLUS expression .) + LESS_THAN reduce using rule 17 (expression -> expression PLUS expression .) + GREATER_EQUALS reduce using rule 17 (expression -> expression PLUS expression .) + GREATER_THAN reduce using rule 17 (expression -> expression PLUS expression .) + IF reduce using rule 17 (expression -> expression PLUS expression .) + STRING_LITERAL reduce using rule 17 (expression -> expression PLUS expression .) + RIGHT_BRACE reduce using rule 17 (expression -> expression PLUS expression .) + RIGHT_BRACKET reduce using rule 17 (expression -> expression PLUS expression .) + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + + ! TIMES [ reduce using rule 17 (expression -> expression PLUS expression .) ] + ! DIVIDE [ reduce using rule 17 (expression -> expression PLUS expression .) ] + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + ! PLUS [ shift and go to state 44 ] + ! MINUS [ shift and go to state 48 ] + ! EQUALS [ shift and go to state 46 ] + ! NOT_EQUALS [ shift and go to state 45 ] + ! LESS_EQUALS [ shift and go to state 54 ] + ! LESS_THAN [ shift and go to state 47 ] + ! GREATER_EQUALS [ shift and go to state 55 ] + ! GREATER_THAN [ shift and go to state 53 ] + + +state 65 + + (22) expression -> expression NOT_EQUALS expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 22 (expression -> expression NOT_EQUALS expression .) + OR reduce using rule 22 (expression -> expression NOT_EQUALS expression .) + EQUALS reduce using rule 22 (expression -> expression NOT_EQUALS expression .) + NOT_EQUALS reduce using rule 22 (expression -> expression NOT_EQUALS expression .) + IF reduce using rule 22 (expression -> expression NOT_EQUALS expression .) + STRING_LITERAL reduce using rule 22 (expression -> expression NOT_EQUALS expression .) + RIGHT_BRACE reduce using rule 22 (expression -> expression NOT_EQUALS expression .) + RIGHT_BRACKET reduce using rule 22 (expression -> expression NOT_EQUALS expression .) + PLUS shift and go to state 44 + MINUS shift and go to state 48 + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + LESS_EQUALS shift and go to state 54 + LESS_THAN shift and go to state 47 + GREATER_EQUALS shift and go to state 55 + GREATER_THAN shift and go to state 53 + + ! PLUS [ reduce using rule 22 (expression -> expression NOT_EQUALS expression .) ] + ! MINUS [ reduce using rule 22 (expression -> expression NOT_EQUALS expression .) ] + ! TIMES [ reduce using rule 22 (expression -> expression NOT_EQUALS expression .) ] + ! DIVIDE [ reduce using rule 22 (expression -> expression NOT_EQUALS expression .) ] + ! LESS_EQUALS [ reduce using rule 22 (expression -> expression NOT_EQUALS expression .) ] + ! LESS_THAN [ reduce using rule 22 (expression -> expression NOT_EQUALS expression .) ] + ! GREATER_EQUALS [ reduce using rule 22 (expression -> expression NOT_EQUALS expression .) ] + ! GREATER_THAN [ reduce using rule 22 (expression -> expression NOT_EQUALS expression .) ] + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + ! EQUALS [ shift and go to state 46 ] + ! NOT_EQUALS [ shift and go to state 45 ] + + +state 66 + + (21) expression -> expression EQUALS expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 21 (expression -> expression EQUALS expression .) + OR reduce using rule 21 (expression -> expression EQUALS expression .) + EQUALS reduce using rule 21 (expression -> expression EQUALS expression .) + NOT_EQUALS reduce using rule 21 (expression -> expression EQUALS expression .) + IF reduce using rule 21 (expression -> expression EQUALS expression .) + STRING_LITERAL reduce using rule 21 (expression -> expression EQUALS expression .) + RIGHT_BRACE reduce using rule 21 (expression -> expression EQUALS expression .) + RIGHT_BRACKET reduce using rule 21 (expression -> expression EQUALS expression .) + PLUS shift and go to state 44 + MINUS shift and go to state 48 + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + LESS_EQUALS shift and go to state 54 + LESS_THAN shift and go to state 47 + GREATER_EQUALS shift and go to state 55 + GREATER_THAN shift and go to state 53 + + ! PLUS [ reduce using rule 21 (expression -> expression EQUALS expression .) ] + ! MINUS [ reduce using rule 21 (expression -> expression EQUALS expression .) ] + ! TIMES [ reduce using rule 21 (expression -> expression EQUALS expression .) ] + ! DIVIDE [ reduce using rule 21 (expression -> expression EQUALS expression .) ] + ! LESS_EQUALS [ reduce using rule 21 (expression -> expression EQUALS expression .) ] + ! LESS_THAN [ reduce using rule 21 (expression -> expression EQUALS expression .) ] + ! GREATER_EQUALS [ reduce using rule 21 (expression -> expression EQUALS expression .) ] + ! GREATER_THAN [ reduce using rule 21 (expression -> expression EQUALS expression .) ] + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + ! EQUALS [ shift and go to state 46 ] + ! NOT_EQUALS [ shift and go to state 45 ] + + +state 67 + + (24) expression -> expression LESS_THAN expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 24 (expression -> expression LESS_THAN expression .) + OR reduce using rule 24 (expression -> expression LESS_THAN expression .) + EQUALS reduce using rule 24 (expression -> expression LESS_THAN expression .) + NOT_EQUALS reduce using rule 24 (expression -> expression LESS_THAN expression .) + LESS_EQUALS reduce using rule 24 (expression -> expression LESS_THAN expression .) + LESS_THAN reduce using rule 24 (expression -> expression LESS_THAN expression .) + GREATER_EQUALS reduce using rule 24 (expression -> expression LESS_THAN expression .) + GREATER_THAN reduce using rule 24 (expression -> expression LESS_THAN expression .) + IF reduce using rule 24 (expression -> expression LESS_THAN expression .) + STRING_LITERAL reduce using rule 24 (expression -> expression LESS_THAN expression .) + RIGHT_BRACE reduce using rule 24 (expression -> expression LESS_THAN expression .) + RIGHT_BRACKET reduce using rule 24 (expression -> expression LESS_THAN expression .) + PLUS shift and go to state 44 + MINUS shift and go to state 48 + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + + ! PLUS [ reduce using rule 24 (expression -> expression LESS_THAN expression .) ] + ! MINUS [ reduce using rule 24 (expression -> expression LESS_THAN expression .) ] + ! TIMES [ reduce using rule 24 (expression -> expression LESS_THAN expression .) ] + ! DIVIDE [ reduce using rule 24 (expression -> expression LESS_THAN expression .) ] + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + ! EQUALS [ shift and go to state 46 ] + ! NOT_EQUALS [ shift and go to state 45 ] + ! LESS_EQUALS [ shift and go to state 54 ] + ! LESS_THAN [ shift and go to state 47 ] + ! GREATER_EQUALS [ shift and go to state 55 ] + ! GREATER_THAN [ shift and go to state 53 ] + + +state 68 + + (18) expression -> expression MINUS expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 18 (expression -> expression MINUS expression .) + OR reduce using rule 18 (expression -> expression MINUS expression .) + PLUS reduce using rule 18 (expression -> expression MINUS expression .) + MINUS reduce using rule 18 (expression -> expression MINUS expression .) + EQUALS reduce using rule 18 (expression -> expression MINUS expression .) + NOT_EQUALS reduce using rule 18 (expression -> expression MINUS expression .) + LESS_EQUALS reduce using rule 18 (expression -> expression MINUS expression .) + LESS_THAN reduce using rule 18 (expression -> expression MINUS expression .) + GREATER_EQUALS reduce using rule 18 (expression -> expression MINUS expression .) + GREATER_THAN reduce using rule 18 (expression -> expression MINUS expression .) + IF reduce using rule 18 (expression -> expression MINUS expression .) + STRING_LITERAL reduce using rule 18 (expression -> expression MINUS expression .) + RIGHT_BRACE reduce using rule 18 (expression -> expression MINUS expression .) + RIGHT_BRACKET reduce using rule 18 (expression -> expression MINUS expression .) + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + + ! TIMES [ reduce using rule 18 (expression -> expression MINUS expression .) ] + ! DIVIDE [ reduce using rule 18 (expression -> expression MINUS expression .) ] + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + ! PLUS [ shift and go to state 44 ] + ! MINUS [ shift and go to state 48 ] + ! EQUALS [ shift and go to state 46 ] + ! NOT_EQUALS [ shift and go to state 45 ] + ! LESS_EQUALS [ shift and go to state 54 ] + ! LESS_THAN [ shift and go to state 47 ] + ! GREATER_EQUALS [ shift and go to state 55 ] + ! GREATER_THAN [ shift and go to state 53 ] + + +state 69 + + (19) expression -> expression TIMES expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 19 (expression -> expression TIMES expression .) + OR reduce using rule 19 (expression -> expression TIMES expression .) + PLUS reduce using rule 19 (expression -> expression TIMES expression .) + MINUS reduce using rule 19 (expression -> expression TIMES expression .) + TIMES reduce using rule 19 (expression -> expression TIMES expression .) + DIVIDE reduce using rule 19 (expression -> expression TIMES expression .) + EQUALS reduce using rule 19 (expression -> expression TIMES expression .) + NOT_EQUALS reduce using rule 19 (expression -> expression TIMES expression .) + LESS_EQUALS reduce using rule 19 (expression -> expression TIMES expression .) + LESS_THAN reduce using rule 19 (expression -> expression TIMES expression .) + GREATER_EQUALS reduce using rule 19 (expression -> expression TIMES expression .) + GREATER_THAN reduce using rule 19 (expression -> expression TIMES expression .) + IF reduce using rule 19 (expression -> expression TIMES expression .) + STRING_LITERAL reduce using rule 19 (expression -> expression TIMES expression .) + RIGHT_BRACE reduce using rule 19 (expression -> expression TIMES expression .) + RIGHT_BRACKET reduce using rule 19 (expression -> expression TIMES expression .) + + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + ! PLUS [ shift and go to state 44 ] + ! MINUS [ shift and go to state 48 ] + ! TIMES [ shift and go to state 49 ] + ! DIVIDE [ shift and go to state 51 ] + ! EQUALS [ shift and go to state 46 ] + ! NOT_EQUALS [ shift and go to state 45 ] + ! LESS_EQUALS [ shift and go to state 54 ] + ! LESS_THAN [ shift and go to state 47 ] + ! GREATER_EQUALS [ shift and go to state 55 ] + ! GREATER_THAN [ shift and go to state 53 ] + + +state 70 + + (16) expression -> expression OR expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + OR reduce using rule 16 (expression -> expression OR expression .) + IF reduce using rule 16 (expression -> expression OR expression .) + STRING_LITERAL reduce using rule 16 (expression -> expression OR expression .) + RIGHT_BRACE reduce using rule 16 (expression -> expression OR expression .) + RIGHT_BRACKET reduce using rule 16 (expression -> expression OR expression .) + AND shift and go to state 52 + PLUS shift and go to state 44 + MINUS shift and go to state 48 + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + EQUALS shift and go to state 46 + NOT_EQUALS shift and go to state 45 + LESS_EQUALS shift and go to state 54 + LESS_THAN shift and go to state 47 + GREATER_EQUALS shift and go to state 55 + GREATER_THAN shift and go to state 53 + + ! AND [ reduce using rule 16 (expression -> expression OR expression .) ] + ! PLUS [ reduce using rule 16 (expression -> expression OR expression .) ] + ! MINUS [ reduce using rule 16 (expression -> expression OR expression .) ] + ! TIMES [ reduce using rule 16 (expression -> expression OR expression .) ] + ! DIVIDE [ reduce using rule 16 (expression -> expression OR expression .) ] + ! EQUALS [ reduce using rule 16 (expression -> expression OR expression .) ] + ! NOT_EQUALS [ reduce using rule 16 (expression -> expression OR expression .) ] + ! LESS_EQUALS [ reduce using rule 16 (expression -> expression OR expression .) ] + ! LESS_THAN [ reduce using rule 16 (expression -> expression OR expression .) ] + ! GREATER_EQUALS [ reduce using rule 16 (expression -> expression OR expression .) ] + ! GREATER_THAN [ reduce using rule 16 (expression -> expression OR expression .) ] + ! OR [ shift and go to state 50 ] + + +state 71 + + (20) expression -> expression DIVIDE expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 20 (expression -> expression DIVIDE expression .) + OR reduce using rule 20 (expression -> expression DIVIDE expression .) + PLUS reduce using rule 20 (expression -> expression DIVIDE expression .) + MINUS reduce using rule 20 (expression -> expression DIVIDE expression .) + TIMES reduce using rule 20 (expression -> expression DIVIDE expression .) + DIVIDE reduce using rule 20 (expression -> expression DIVIDE expression .) + EQUALS reduce using rule 20 (expression -> expression DIVIDE expression .) + NOT_EQUALS reduce using rule 20 (expression -> expression DIVIDE expression .) + LESS_EQUALS reduce using rule 20 (expression -> expression DIVIDE expression .) + LESS_THAN reduce using rule 20 (expression -> expression DIVIDE expression .) + GREATER_EQUALS reduce using rule 20 (expression -> expression DIVIDE expression .) + GREATER_THAN reduce using rule 20 (expression -> expression DIVIDE expression .) + IF reduce using rule 20 (expression -> expression DIVIDE expression .) + STRING_LITERAL reduce using rule 20 (expression -> expression DIVIDE expression .) + RIGHT_BRACE reduce using rule 20 (expression -> expression DIVIDE expression .) + RIGHT_BRACKET reduce using rule 20 (expression -> expression DIVIDE expression .) + + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + ! PLUS [ shift and go to state 44 ] + ! MINUS [ shift and go to state 48 ] + ! TIMES [ shift and go to state 49 ] + ! DIVIDE [ shift and go to state 51 ] + ! EQUALS [ shift and go to state 46 ] + ! NOT_EQUALS [ shift and go to state 45 ] + ! LESS_EQUALS [ shift and go to state 54 ] + ! LESS_THAN [ shift and go to state 47 ] + ! GREATER_EQUALS [ shift and go to state 55 ] + ! GREATER_THAN [ shift and go to state 53 ] + + +state 72 + + (15) expression -> expression AND expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 15 (expression -> expression AND expression .) + OR reduce using rule 15 (expression -> expression AND expression .) + IF reduce using rule 15 (expression -> expression AND expression .) + STRING_LITERAL reduce using rule 15 (expression -> expression AND expression .) + RIGHT_BRACE reduce using rule 15 (expression -> expression AND expression .) + RIGHT_BRACKET reduce using rule 15 (expression -> expression AND expression .) + PLUS shift and go to state 44 + MINUS shift and go to state 48 + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + EQUALS shift and go to state 46 + NOT_EQUALS shift and go to state 45 + LESS_EQUALS shift and go to state 54 + LESS_THAN shift and go to state 47 + GREATER_EQUALS shift and go to state 55 + GREATER_THAN shift and go to state 53 + + ! PLUS [ reduce using rule 15 (expression -> expression AND expression .) ] + ! MINUS [ reduce using rule 15 (expression -> expression AND expression .) ] + ! TIMES [ reduce using rule 15 (expression -> expression AND expression .) ] + ! DIVIDE [ reduce using rule 15 (expression -> expression AND expression .) ] + ! EQUALS [ reduce using rule 15 (expression -> expression AND expression .) ] + ! NOT_EQUALS [ reduce using rule 15 (expression -> expression AND expression .) ] + ! LESS_EQUALS [ reduce using rule 15 (expression -> expression AND expression .) ] + ! LESS_THAN [ reduce using rule 15 (expression -> expression AND expression .) ] + ! GREATER_EQUALS [ reduce using rule 15 (expression -> expression AND expression .) ] + ! GREATER_THAN [ reduce using rule 15 (expression -> expression AND expression .) ] + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + + +state 73 + + (26) expression -> expression GREATER_THAN expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 26 (expression -> expression GREATER_THAN expression .) + OR reduce using rule 26 (expression -> expression GREATER_THAN expression .) + EQUALS reduce using rule 26 (expression -> expression GREATER_THAN expression .) + NOT_EQUALS reduce using rule 26 (expression -> expression GREATER_THAN expression .) + LESS_EQUALS reduce using rule 26 (expression -> expression GREATER_THAN expression .) + LESS_THAN reduce using rule 26 (expression -> expression GREATER_THAN expression .) + GREATER_EQUALS reduce using rule 26 (expression -> expression GREATER_THAN expression .) + GREATER_THAN reduce using rule 26 (expression -> expression GREATER_THAN expression .) + IF reduce using rule 26 (expression -> expression GREATER_THAN expression .) + STRING_LITERAL reduce using rule 26 (expression -> expression GREATER_THAN expression .) + RIGHT_BRACE reduce using rule 26 (expression -> expression GREATER_THAN expression .) + RIGHT_BRACKET reduce using rule 26 (expression -> expression GREATER_THAN expression .) + PLUS shift and go to state 44 + MINUS shift and go to state 48 + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + + ! PLUS [ reduce using rule 26 (expression -> expression GREATER_THAN expression .) ] + ! MINUS [ reduce using rule 26 (expression -> expression GREATER_THAN expression .) ] + ! TIMES [ reduce using rule 26 (expression -> expression GREATER_THAN expression .) ] + ! DIVIDE [ reduce using rule 26 (expression -> expression GREATER_THAN expression .) ] + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + ! EQUALS [ shift and go to state 46 ] + ! NOT_EQUALS [ shift and go to state 45 ] + ! LESS_EQUALS [ shift and go to state 54 ] + ! LESS_THAN [ shift and go to state 47 ] + ! GREATER_EQUALS [ shift and go to state 55 ] + ! GREATER_THAN [ shift and go to state 53 ] + + +state 74 + + (23) expression -> expression LESS_EQUALS expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 23 (expression -> expression LESS_EQUALS expression .) + OR reduce using rule 23 (expression -> expression LESS_EQUALS expression .) + EQUALS reduce using rule 23 (expression -> expression LESS_EQUALS expression .) + NOT_EQUALS reduce using rule 23 (expression -> expression LESS_EQUALS expression .) + LESS_EQUALS reduce using rule 23 (expression -> expression LESS_EQUALS expression .) + LESS_THAN reduce using rule 23 (expression -> expression LESS_EQUALS expression .) + GREATER_EQUALS reduce using rule 23 (expression -> expression LESS_EQUALS expression .) + GREATER_THAN reduce using rule 23 (expression -> expression LESS_EQUALS expression .) + IF reduce using rule 23 (expression -> expression LESS_EQUALS expression .) + STRING_LITERAL reduce using rule 23 (expression -> expression LESS_EQUALS expression .) + RIGHT_BRACE reduce using rule 23 (expression -> expression LESS_EQUALS expression .) + RIGHT_BRACKET reduce using rule 23 (expression -> expression LESS_EQUALS expression .) + PLUS shift and go to state 44 + MINUS shift and go to state 48 + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + + ! PLUS [ reduce using rule 23 (expression -> expression LESS_EQUALS expression .) ] + ! MINUS [ reduce using rule 23 (expression -> expression LESS_EQUALS expression .) ] + ! TIMES [ reduce using rule 23 (expression -> expression LESS_EQUALS expression .) ] + ! DIVIDE [ reduce using rule 23 (expression -> expression LESS_EQUALS expression .) ] + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + ! EQUALS [ shift and go to state 46 ] + ! NOT_EQUALS [ shift and go to state 45 ] + ! LESS_EQUALS [ shift and go to state 54 ] + ! LESS_THAN [ shift and go to state 47 ] + ! GREATER_EQUALS [ shift and go to state 55 ] + ! GREATER_THAN [ shift and go to state 53 ] + + +state 75 + + (25) expression -> expression GREATER_EQUALS expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + AND reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) + OR reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) + EQUALS reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) + NOT_EQUALS reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) + LESS_EQUALS reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) + LESS_THAN reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) + GREATER_EQUALS reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) + GREATER_THAN reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) + IF reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) + STRING_LITERAL reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) + RIGHT_BRACE reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) + RIGHT_BRACKET reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) + PLUS shift and go to state 44 + MINUS shift and go to state 48 + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + + ! PLUS [ reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) ] + ! MINUS [ reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) ] + ! TIMES [ reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) ] + ! DIVIDE [ reduce using rule 25 (expression -> expression GREATER_EQUALS expression .) ] + ! AND [ shift and go to state 52 ] + ! OR [ shift and go to state 50 ] + ! EQUALS [ shift and go to state 46 ] + ! NOT_EQUALS [ shift and go to state 45 ] + ! LESS_EQUALS [ shift and go to state 54 ] + ! LESS_THAN [ shift and go to state 47 ] + ! GREATER_EQUALS [ shift and go to state 55 ] + ! GREATER_THAN [ shift and go to state 53 ] + + +state 76 + + (8) question -> STRING_LITERAL IDENTIFIER COLON type ASSIGN . expression + (11) expression -> . LEFT_BRACKET expression RIGHT_BRACKET + (12) expression -> . IDENTIFIER + (13) expression -> . NOT expression + (14) expression -> . MINUS expression + (15) expression -> . expression AND expression + (16) expression -> . expression OR expression + (17) expression -> . expression PLUS expression + (18) expression -> . expression MINUS expression + (19) expression -> . expression TIMES expression + (20) expression -> . expression DIVIDE expression + (21) expression -> . expression EQUALS expression + (22) expression -> . expression NOT_EQUALS expression + (23) expression -> . expression LESS_EQUALS expression + (24) expression -> . expression LESS_THAN expression + (25) expression -> . expression GREATER_EQUALS expression + (26) expression -> . expression GREATER_THAN expression + (27) expression -> . FALSE + (28) expression -> . TRUE + (29) expression -> . DATE_LITERAL + (30) expression -> . INTEGER_LITERAL + (31) expression -> . DECIMAL_LITERAL + (32) expression -> . currency DECIMAL_LITERAL + (33) expression -> . currency INTEGER_LITERAL + (34) expression -> . STRING_LITERAL + (35) currency -> . DOLLAR + (36) currency -> . RUBLE + + LEFT_BRACKET shift and go to state 30 + IDENTIFIER shift and go to state 34 + NOT shift and go to state 27 + MINUS shift and go to state 25 + FALSE shift and go to state 35 + TRUE shift and go to state 32 + DATE_LITERAL shift and go to state 24 + INTEGER_LITERAL shift and go to state 26 + DECIMAL_LITERAL shift and go to state 31 + STRING_LITERAL shift and go to state 28 + DOLLAR shift and go to state 29 + RUBLE shift and go to state 23 + + expression shift and go to state 77 + currency shift and go to state 22 + +state 77 + + (8) question -> STRING_LITERAL IDENTIFIER COLON type ASSIGN expression . + (15) expression -> expression . AND expression + (16) expression -> expression . OR expression + (17) expression -> expression . PLUS expression + (18) expression -> expression . MINUS expression + (19) expression -> expression . TIMES expression + (20) expression -> expression . DIVIDE expression + (21) expression -> expression . EQUALS expression + (22) expression -> expression . NOT_EQUALS expression + (23) expression -> expression . LESS_EQUALS expression + (24) expression -> expression . LESS_THAN expression + (25) expression -> expression . GREATER_EQUALS expression + (26) expression -> expression . GREATER_THAN expression + + IF reduce using rule 8 (question -> STRING_LITERAL IDENTIFIER COLON type ASSIGN expression .) + STRING_LITERAL reduce using rule 8 (question -> STRING_LITERAL IDENTIFIER COLON type ASSIGN expression .) + RIGHT_BRACE reduce using rule 8 (question -> STRING_LITERAL IDENTIFIER COLON type ASSIGN expression .) + AND shift and go to state 52 + OR shift and go to state 50 + PLUS shift and go to state 44 + MINUS shift and go to state 48 + TIMES shift and go to state 49 + DIVIDE shift and go to state 51 + EQUALS shift and go to state 46 + NOT_EQUALS shift and go to state 45 + LESS_EQUALS shift and go to state 54 + LESS_THAN shift and go to state 47 + GREATER_EQUALS shift and go to state 55 + GREATER_THAN shift and go to state 53 + diff --git a/ql/parser/parser.py b/ql/parser/parser.py new file mode 100644 index 0000000..d962a0f --- /dev/null +++ b/ql/parser/parser.py @@ -0,0 +1,319 @@ +from ply.yacc import yacc + +from ql.ast.nodes.expressions.binary_operators.addition_operator import AdditionOperatorNode +from ql.ast.nodes.expressions.binary_operators.and_operator import AndOperatorNode +from ql.ast.nodes.expressions.binary_operators.division_operator import DivisionOperatorNode +from ql.ast.nodes.expressions.binary_operators.equals_operator import EqualsOperatorNode +from ql.ast.nodes.expressions.binary_operators.greater_equals_operator import GreaterEqualsOperatorNode +from ql.ast.nodes.expressions.binary_operators.greater_than_operator import GreaterThanOperatorNode +from ql.ast.nodes.expressions.binary_operators.less_equals_operator import LessEqualsOperatorNode +from ql.ast.nodes.expressions.binary_operators.less_than_operator import LessThanOperatorNode +from ql.ast.nodes.expressions.binary_operators.multiplication_operator import MultiplicationOperatorNode +from ql.ast.nodes.expressions.binary_operators.not_equals_operator import NotEqualsOperatorNode +from ql.ast.nodes.expressions.binary_operators.or_operator import OrOperatorNode +from ql.ast.nodes.expressions.binary_operators.subtraction_operator import SubtractionOperatorNode +from ql.ast.nodes.expressions.literals.boolean_literal import BooleanNode +from ql.ast.nodes.expressions.literals.date_literal import DateNode +from ql.ast.nodes.expressions.literals.decimal_literal import DecimalNode +from ql.ast.nodes.expressions.literals.integer_literal import IntegerNode +from ql.ast.nodes.expressions.literals.money_literal import MoneyNode +from ql.ast.nodes.expressions.literals.string_literal import StringNode +from ql.ast.nodes.expressions.unary_operators.negation_operator import NegationOperatorNode +from ql.ast.nodes.expressions.unary_operators.negative_operator import NegativeOperatorNode +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.parser.lexer import QLLexer +from ql.parser.metadata import Metadata +from ql.types.boolean import QLBoolean +from ql.types.date import QLDate +from ql.types.decimal import QLDecimal +from ql.types.integer import QLInteger +from ql.types.money import QLMoney +from ql.types.string import QLString +from ql.types.undefined import QLUndefined + + +class QLParser: + def __init__(self): + self.__errors = [] + self.__tokens = QLLexer.tokens + self.__parser = None + self.__precedence = ( + ('left', 'OR'), + ('left', 'AND'), + ('nonassoc', 'EQUALS', 'NOT_EQUALS'), + ('nonassoc', 'LESS_EQUALS', 'LESS_THAN', 'GREATER_EQUALS', 'GREATER_THAN'), + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE'), + ('right', 'NOT'), + ) + + @property + def errors(self): + return self.__errors + + @property + def tokens(self): + return self.__tokens + + @property + def parser(self): + return self.__parser + + @property + def precedence(self): + return self.__precedence + + def build(self): + self.__parser = yacc(module=self) + + def parse(self, data, lexer): + self.__errors = [] + return self.parser.parse(data, lexer) + + # Grammar + @staticmethod + def p_form(production): + """form : FORM IDENTIFIER block""" + production[0] = FormNode(Metadata(production.lineno(1)), production[3], production[2]) + + @staticmethod + def p_block(production): + """block : LEFT_BRACE statements RIGHT_BRACE""" + production[0] = production[2] + + # Statements + @staticmethod + def p_statements(production): + """statements : statement statements + | statement""" + if len(production) == 3: + production[0] = [production[1]] + production[2] + elif len(production) == 2: + production[0] = [production[1]] + + @staticmethod + def p_statement(production): + """statement : if + | question""" + production[0] = production[1] + + # Questions + @staticmethod + def p_question(production): + """question : STRING_LITERAL IDENTIFIER COLON type""" + production[0] = QuestionNode(Metadata(production.lineno(1)), production[1], production[2], + production[4], production[4].get_literal_node(production[4]()), False) + + @staticmethod + def p_question_computed(production): + """question : STRING_LITERAL IDENTIFIER COLON type ASSIGN expression""" + production[0] = QuestionNode(Metadata(production.lineno(1)), production[1], production[2], + production[4], production[6], True) + + # Control flow + @staticmethod + def p_if(production): + """if : IF condition block""" + production[0] = IfNode(Metadata(production.lineno(1)), production[3], production[2]) + + @staticmethod + def p_condition(production): + """condition : LEFT_BRACKET expression RIGHT_BRACKET""" + production[0] = production[2] + + # Expressions + @staticmethod + def p_parenthesis(production): + """expression : LEFT_BRACKET expression RIGHT_BRACKET""" + production[0] = production[2] + + @staticmethod + def p_variable(production): + """expression : IDENTIFIER""" + production[0] = VariableNode(Metadata(production.lineno(1)), QLUndefined, production[1], + QLUndefined()) + + # Unary operators + @staticmethod + def p_not(production): + """expression : NOT expression""" + production[0] = NegationOperatorNode(Metadata(production.lineno(1)), QLBoolean, + production[2], QLUndefined()) + + @staticmethod + def p_negative(production): + """expression : MINUS expression""" + production[0] = NegativeOperatorNode(Metadata(production.lineno(1)), QLUndefined, + production[2], QLUndefined()) + + # Binary operators + @staticmethod + def p_and(production): + """expression : expression AND expression""" + production[0] = AndOperatorNode(Metadata(production.lineno(2)), QLBoolean, production[1], + production[3], QLUndefined()) + + @staticmethod + def p_or(production): + """expression : expression OR expression""" + production[0] = OrOperatorNode(Metadata(production.lineno(2)), QLBoolean, production[1], + production[3], QLUndefined()) + + @staticmethod + def p_plus(production): + """expression : expression PLUS expression""" + production[0] = AdditionOperatorNode(Metadata(production.lineno(2)), QLUndefined, + production[1], production[3], QLUndefined()) + + @staticmethod + def p_minus(production): + """expression : expression MINUS expression""" + production[0] = SubtractionOperatorNode(Metadata(production.lineno(2)), QLUndefined, + production[1], production[3], QLUndefined()) + + @staticmethod + def p_times(production): + """expression : expression TIMES expression""" + production[0] = MultiplicationOperatorNode(Metadata(production.lineno(2)), QLUndefined, + production[1], production[3], QLUndefined()) + + @staticmethod + def p_divide(production): + """expression : expression DIVIDE expression""" + production[0] = DivisionOperatorNode(Metadata(production.lineno(2)), QLUndefined, + production[1], production[3], QLUndefined()) + + @staticmethod + def p_equals(production): + """expression : expression EQUALS expression""" + production[0] = EqualsOperatorNode(Metadata(production.lineno(2)), QLBoolean, + production[1], production[3], QLUndefined()) + + @staticmethod + def p_not_equals(production): + """expression : expression NOT_EQUALS expression""" + production[0] = NotEqualsOperatorNode(Metadata(production.lineno(2)), QLBoolean, + production[1], production[3], QLUndefined()) + + @staticmethod + def p_less_equals(production): + """expression : expression LESS_EQUALS expression""" + production[0] = LessEqualsOperatorNode(Metadata(production.lineno(2)), QLBoolean, + production[1], production[3], QLUndefined()) + + @staticmethod + def p_less_than(production): + """expression : expression LESS_THAN expression""" + production[0] = LessThanOperatorNode(Metadata(production.lineno(2)), QLBoolean, + production[1], production[3], QLUndefined()) + + @staticmethod + def p_greater_equals(production): + """expression : expression GREATER_EQUALS expression""" + production[0] = GreaterEqualsOperatorNode(Metadata(production.lineno(2)), QLBoolean, + production[1], production[3], QLUndefined()) + + @staticmethod + def p_greater_than(production): + """expression : expression GREATER_THAN expression""" + production[0] = GreaterThanOperatorNode(Metadata(production.lineno(2)), QLBoolean, + production[1], production[3], QLUndefined()) + + # Literals + @staticmethod + def p_boolean_literal(production): + """expression : FALSE + | TRUE""" + production[0] = BooleanNode(Metadata(production.lineno(1)), QLBoolean, QLBoolean(production[1])) + + @staticmethod + def p_date_literal(production): + """expression : DATE_LITERAL""" + day, month, year = production[1] + production[0] = DateNode(Metadata(production.lineno(1)), QLDate, QLDate(day, month, year)) + + @staticmethod + def p_integer_literal(production): + """expression : INTEGER_LITERAL""" + production[0] = IntegerNode(Metadata(production.lineno(1)), QLInteger, QLInteger(production[1])) + + @staticmethod + def p_decimal_literal(production): + """expression : DECIMAL_LITERAL""" + production[0] = DecimalNode(Metadata(production.lineno(1)), QLDecimal, QLDecimal(production[1])) + + @staticmethod + def p_money_literal(production): + """expression : currency DECIMAL_LITERAL + | currency INTEGER_LITERAL""" + production[0] = MoneyNode(Metadata(production.lineno(1)), QLMoney, + QLMoney(production[2], production[1])) + + @staticmethod + def p_string_literal(production): + """expression : STRING_LITERAL""" + production[0] = StringNode(Metadata(production.lineno(1)), QLString, QLString([1])) + + # Currencies + @staticmethod + def p_currency(production): + """currency : DOLLAR + | RUBLE""" + production[0] = production[1] + + # Types + @staticmethod + def p_boolean(production): + """type : BOOLEAN""" + production[0] = QLBoolean + + @staticmethod + def p_decimal(production): + """type : DECIMAL""" + production[0] = QLDecimal + + @staticmethod + def p_string(production): + """type : STRING""" + production[0] = QLString + + @staticmethod + def p_date(production): + """type : DATE""" + production[0] = QLDate + + @staticmethod + def p_money(production): + """type : MONEY""" + production[0] = QLMoney + + @staticmethod + def p_integer(production): + """type : INTEGER""" + production[0] = QLInteger + + # Error + def p_error(self, production): + if production is None: + self.errors.append('Syntax error.') + else: + self.errors.append('Syntax error at line {}, token={}.'.format(production.lineno, production.type)) + + def p_form_label(self, production): + """form : FORM LEFT_BRACE""" + self.errors.append('Missing form identifier at line {}.'.format(production.lineno(1))) + + def p_empty_form(self, production): + """form : FORM IDENTIFIER LEFT_BRACE RIGHT_BRACE""" + self.errors.append('Empty form at line {}.'.format(production.lineno(1))) + + def p_empty_if(self, production): + """statement : IF condition LEFT_BRACE RIGHT_BRACE""" + self.errors.append('Empty if block at line {}.'.format(production.lineno(1))) + + def p_empty_condition(self, production): + """condition : LEFT_BRACKET RIGHT_BRACKET""" + self.errors.append('Empty conditional at line {}.'.format(production.lineno(1))) diff --git a/ql/parser/parsetab.py b/ql/parser/parsetab.py new file mode 100644 index 0000000..b978ef8 --- /dev/null +++ b/ql/parser/parsetab.py @@ -0,0 +1,76 @@ + +# parsetab.py +# This file is automatically generated. Do not edit. +# pylint: disable=W,C,R +_tabversion = '3.10' + +_lr_method = 'LALR' + +_lr_signature = 'leftORleftANDnonassocEQUALSNOT_EQUALSnonassocLESS_EQUALSLESS_THANGREATER_EQUALSGREATER_THANleftPLUSMINUSleftTIMESDIVIDErightNOTAND ASSIGN BOOLEAN COLON DATE DATE_LITERAL DECIMAL DECIMAL_LITERAL DIVIDE DOLLAR EQUALS FALSE FORM GREATER_EQUALS GREATER_THAN IDENTIFIER IF INTEGER INTEGER_LITERAL LEFT_BRACE LEFT_BRACKET LESS_EQUALS LESS_THAN MINUS MONEY NOT NOT_EQUALS OR PLUS RIGHT_BRACE RIGHT_BRACKET RUBLE STRING STRING_LITERAL TIMES TRUEform : FORM IDENTIFIER blockblock : LEFT_BRACE statements RIGHT_BRACEstatements : statement statements\n | statementstatement : if\n | questionquestion : STRING_LITERAL IDENTIFIER COLON typequestion : STRING_LITERAL IDENTIFIER COLON type ASSIGN expressionif : IF condition blockcondition : LEFT_BRACKET expression RIGHT_BRACKETexpression : LEFT_BRACKET expression RIGHT_BRACKETexpression : IDENTIFIERexpression : NOT expressionexpression : MINUS expressionexpression : expression AND expressionexpression : expression OR expressionexpression : expression PLUS expressionexpression : expression MINUS expressionexpression : expression TIMES expressionexpression : expression DIVIDE expressionexpression : expression EQUALS expressionexpression : expression NOT_EQUALS expressionexpression : expression LESS_EQUALS expressionexpression : expression LESS_THAN expressionexpression : expression GREATER_EQUALS expressionexpression : expression GREATER_THAN expressionexpression : FALSE\n | TRUEexpression : DATE_LITERALexpression : INTEGER_LITERALexpression : DECIMAL_LITERALexpression : currency DECIMAL_LITERAL\n | currency INTEGER_LITERALexpression : STRING_LITERALcurrency : DOLLAR\n | RUBLEtype : BOOLEANtype : DECIMALtype : STRINGtype : DATEtype : MONEYtype : INTEGERform : FORM LEFT_BRACEform : FORM IDENTIFIER LEFT_BRACE RIGHT_BRACEstatement : IF condition LEFT_BRACE RIGHT_BRACEcondition : LEFT_BRACKET RIGHT_BRACKET' + +_lr_action_items = {'RIGHT_BRACKET':([17,24,26,28,31,32,33,34,35,38,39,40,41,42,63,64,65,66,67,68,69,70,71,72,73,74,75,],[21,-29,-30,-34,-31,-28,43,-12,-27,-32,-33,-14,-13,63,-11,-17,-22,-21,-24,-18,-19,-16,-20,-15,-26,-23,-25,]),'TRUE':([17,25,27,30,44,45,46,47,48,49,50,51,52,53,54,55,76,],[32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,]),'LEFT_BRACE':([1,3,16,21,43,],[4,5,19,-46,-10,]),'RUBLE':([17,25,27,30,44,45,46,47,48,49,50,51,52,53,54,55,76,],[23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,]),'DATE_LITERAL':([17,25,27,30,44,45,46,47,48,49,50,51,52,53,54,55,76,],[24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,]),'MINUS':([17,24,25,26,27,28,30,31,32,33,34,35,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,],[25,-29,25,-30,25,-34,25,-31,-28,48,-12,-27,-32,-33,-14,-13,48,25,25,25,25,25,25,25,25,25,25,25,25,-11,-17,48,48,48,-18,-19,48,-20,48,48,48,48,25,48,]),'INTEGER_LITERAL':([17,22,23,25,27,29,30,44,45,46,47,48,49,50,51,52,53,54,55,76,],[26,39,-36,26,26,-35,26,26,26,26,26,26,26,26,26,26,26,26,26,26,]),'TIMES':([24,26,28,31,32,33,34,35,38,39,40,41,42,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[-29,-30,-34,-31,-28,49,-12,-27,-32,-33,49,-13,49,-11,49,49,49,49,49,-19,49,-20,49,49,49,49,49,]),'NOT':([17,25,27,30,44,45,46,47,48,49,50,51,52,53,54,55,76,],[27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,]),'DOLLAR':([17,25,27,30,44,45,46,47,48,49,50,51,52,53,54,55,76,],[29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,]),'MONEY':([36,],[60,]),'INTEGER':([36,],[61,]),'AND':([24,26,28,31,32,33,34,35,38,39,40,41,42,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[-29,-30,-34,-31,-28,52,-12,-27,-32,-33,-14,-13,52,-11,-17,-22,-21,-24,-18,-19,52,-20,-15,-26,-23,-25,52,]),'NOT_EQUALS':([24,26,28,31,32,33,34,35,38,39,40,41,42,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[-29,-30,-34,-31,-28,45,-12,-27,-32,-33,-14,-13,45,-11,-17,None,None,-24,-18,-19,45,-20,45,-26,-23,-25,45,]),'ASSIGN':([56,57,58,59,60,61,62,],[-40,-38,-39,76,-41,-42,-37,]),'BOOLEAN':([36,],[62,]),'FORM':([0,],[1,]),'IF':([5,7,8,10,14,19,20,24,26,28,31,32,34,35,37,38,39,40,41,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[11,-5,-6,11,-2,11,-9,-29,-30,-34,-31,-28,-12,-27,-45,-32,-33,-14,-13,-40,-38,-39,-7,-41,-42,-37,-11,-17,-22,-21,-24,-18,-19,-16,-20,-15,-26,-23,-25,-8,]),'LEFT_BRACKET':([11,17,25,27,30,44,45,46,47,48,49,50,51,52,53,54,55,76,],[17,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,]),'PLUS':([24,26,28,31,32,33,34,35,38,39,40,41,42,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[-29,-30,-34,-31,-28,44,-12,-27,-32,-33,-14,-13,44,-11,-17,44,44,44,-18,-19,44,-20,44,44,44,44,44,]),'$end':([2,4,6,13,14,],[0,-43,-1,-44,-2,]),'EQUALS':([24,26,28,31,32,33,34,35,38,39,40,41,42,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[-29,-30,-34,-31,-28,46,-12,-27,-32,-33,-14,-13,46,-11,-17,None,None,-24,-18,-19,46,-20,46,-26,-23,-25,46,]),'IDENTIFIER':([1,12,17,25,27,30,44,45,46,47,48,49,50,51,52,53,54,55,76,],[3,18,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,]),'LESS_THAN':([24,26,28,31,32,33,34,35,38,39,40,41,42,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[-29,-30,-34,-31,-28,47,-12,-27,-32,-33,-14,-13,47,-11,-17,47,47,None,-18,-19,47,-20,47,None,None,None,47,]),'STRING':([36,],[58,]),'COLON':([18,],[36,]),'DATE':([36,],[56,]),'STRING_LITERAL':([5,7,8,10,14,17,19,20,24,25,26,27,28,30,31,32,34,35,37,38,39,40,41,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,],[12,-5,-6,12,-2,28,12,-9,-29,28,-30,28,-34,28,-31,-28,-12,-27,-45,-32,-33,-14,-13,28,28,28,28,28,28,28,28,28,28,28,28,-40,-38,-39,-7,-41,-42,-37,-11,-17,-22,-21,-24,-18,-19,-16,-20,-15,-26,-23,-25,28,-8,]),'DECIMAL_LITERAL':([17,22,23,25,27,29,30,44,45,46,47,48,49,50,51,52,53,54,55,76,],[31,38,-36,31,31,-35,31,31,31,31,31,31,31,31,31,31,31,31,31,31,]),'OR':([24,26,28,31,32,33,34,35,38,39,40,41,42,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[-29,-30,-34,-31,-28,50,-12,-27,-32,-33,-14,-13,50,-11,-17,-22,-21,-24,-18,-19,-16,-20,-15,-26,-23,-25,50,]),'FALSE':([17,25,27,30,44,45,46,47,48,49,50,51,52,53,54,55,76,],[35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,]),'DECIMAL':([36,],[57,]),'DIVIDE':([24,26,28,31,32,33,34,35,38,39,40,41,42,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[-29,-30,-34,-31,-28,51,-12,-27,-32,-33,51,-13,51,-11,51,51,51,51,51,-19,51,-20,51,51,51,51,51,]),'LESS_EQUALS':([24,26,28,31,32,33,34,35,38,39,40,41,42,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[-29,-30,-34,-31,-28,54,-12,-27,-32,-33,-14,-13,54,-11,-17,54,54,None,-18,-19,54,-20,54,None,None,None,54,]),'RIGHT_BRACE':([5,7,8,9,10,14,15,19,20,24,26,28,31,32,34,35,37,38,39,40,41,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[13,-5,-6,14,-4,-2,-3,37,-9,-29,-30,-34,-31,-28,-12,-27,-45,-32,-33,-14,-13,-40,-38,-39,-7,-41,-42,-37,-11,-17,-22,-21,-24,-18,-19,-16,-20,-15,-26,-23,-25,-8,]),'GREATER_EQUALS':([24,26,28,31,32,33,34,35,38,39,40,41,42,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[-29,-30,-34,-31,-28,55,-12,-27,-32,-33,-14,-13,55,-11,-17,55,55,None,-18,-19,55,-20,55,None,None,None,55,]),'GREATER_THAN':([24,26,28,31,32,33,34,35,38,39,40,41,42,63,64,65,66,67,68,69,70,71,72,73,74,75,77,],[-29,-30,-34,-31,-28,53,-12,-27,-32,-33,-14,-13,53,-11,-17,53,53,None,-18,-19,53,-20,53,None,None,None,53,]),} + +_lr_action = {} +for _k, _v in _lr_action_items.items(): + for _x,_y in zip(_v[0],_v[1]): + if not _x in _lr_action: _lr_action[_x] = {} + _lr_action[_x][_k] = _y +del _lr_action_items + +_lr_goto_items = {'if':([5,10,19,],[7,7,7,]),'condition':([11,],[16,]),'question':([5,10,19,],[8,8,8,]),'expression':([17,25,27,30,44,45,46,47,48,49,50,51,52,53,54,55,76,],[33,40,41,42,64,65,66,67,68,69,70,71,72,73,74,75,77,]),'currency':([17,25,27,30,44,45,46,47,48,49,50,51,52,53,54,55,76,],[22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,]),'type':([36,],[59,]),'statements':([5,10,19,],[9,15,9,]),'statement':([5,10,19,],[10,10,10,]),'form':([0,],[2,]),'block':([3,16,],[6,20,]),} + +_lr_goto = {} +for _k, _v in _lr_goto_items.items(): + for _x, _y in zip(_v[0], _v[1]): + if not _x in _lr_goto: _lr_goto[_x] = {} + _lr_goto[_x][_k] = _y +del _lr_goto_items +_lr_productions = [ + ("S' -> form","S'",1,None,None,None), + ('form -> FORM IDENTIFIER block','form',3,'p_form','parser.py',78), + ('block -> LEFT_BRACE statements RIGHT_BRACE','block',3,'p_block','parser.py',83), + ('statements -> statement statements','statements',2,'p_statements','parser.py',89), + ('statements -> statement','statements',1,'p_statements','parser.py',90), + ('statement -> if','statement',1,'p_statement','parser.py',98), + ('statement -> question','statement',1,'p_statement','parser.py',99), + ('question -> STRING_LITERAL IDENTIFIER COLON type','question',4,'p_question','parser.py',105), + ('question -> STRING_LITERAL IDENTIFIER COLON type ASSIGN expression','question',6,'p_question_computed','parser.py',111), + ('if -> IF condition block','if',3,'p_if','parser.py',118), + ('condition -> LEFT_BRACKET expression RIGHT_BRACKET','condition',3,'p_condition','parser.py',123), + ('expression -> LEFT_BRACKET expression RIGHT_BRACKET','expression',3,'p_parenthesis','parser.py',129), + ('expression -> IDENTIFIER','expression',1,'p_variable','parser.py',134), + ('expression -> NOT expression','expression',2,'p_not','parser.py',141), + ('expression -> MINUS expression','expression',2,'p_negative','parser.py',147), + ('expression -> expression AND expression','expression',3,'p_and','parser.py',154), + ('expression -> expression OR expression','expression',3,'p_or','parser.py',160), + ('expression -> expression PLUS expression','expression',3,'p_plus','parser.py',166), + ('expression -> expression MINUS expression','expression',3,'p_minus','parser.py',172), + ('expression -> expression TIMES expression','expression',3,'p_times','parser.py',178), + ('expression -> expression DIVIDE expression','expression',3,'p_divide','parser.py',184), + ('expression -> expression EQUALS expression','expression',3,'p_equals','parser.py',190), + ('expression -> expression NOT_EQUALS expression','expression',3,'p_not_equals','parser.py',196), + ('expression -> expression LESS_EQUALS expression','expression',3,'p_less_equals','parser.py',202), + ('expression -> expression LESS_THAN expression','expression',3,'p_less_than','parser.py',208), + ('expression -> expression GREATER_EQUALS expression','expression',3,'p_greater_equals','parser.py',214), + ('expression -> expression GREATER_THAN expression','expression',3,'p_greater_than','parser.py',220), + ('expression -> FALSE','expression',1,'p_boolean_literal','parser.py',227), + ('expression -> TRUE','expression',1,'p_boolean_literal','parser.py',228), + ('expression -> DATE_LITERAL','expression',1,'p_date_literal','parser.py',233), + ('expression -> INTEGER_LITERAL','expression',1,'p_integer_literal','parser.py',238), + ('expression -> DECIMAL_LITERAL','expression',1,'p_decimal_literal','parser.py',243), + ('expression -> currency DECIMAL_LITERAL','expression',2,'p_money_literal','parser.py',248), + ('expression -> currency INTEGER_LITERAL','expression',2,'p_money_literal','parser.py',249), + ('expression -> STRING_LITERAL','expression',1,'p_string_literal','parser.py',255), + ('currency -> DOLLAR','currency',1,'p_currency','parser.py',261), + ('currency -> RUBLE','currency',1,'p_currency','parser.py',262), + ('type -> BOOLEAN','type',1,'p_boolean','parser.py',268), + ('type -> DECIMAL','type',1,'p_decimal','parser.py',273), + ('type -> STRING','type',1,'p_string','parser.py',278), + ('type -> DATE','type',1,'p_date','parser.py',283), + ('type -> MONEY','type',1,'p_money','parser.py',288), + ('type -> INTEGER','type',1,'p_integer','parser.py',293), + ('form -> FORM LEFT_BRACE','form',2,'p_form_label','parser.py',305), + ('form -> FORM IDENTIFIER LEFT_BRACE RIGHT_BRACE','form',4,'p_empty_form','parser.py',309), + ('statement -> IF condition LEFT_BRACE RIGHT_BRACE','statement',4,'p_empty_if','parser.py',313), + ('condition -> LEFT_BRACKET RIGHT_BRACKET','condition',2,'p_empty_condition','parser.py',317), +] diff --git a/ql/test/__pycache__/test.cpython-35.pyc b/ql/test/__pycache__/test.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..2eb18b1 --- /dev/null +++ b/ql/test/__pycache__/test.cpython-35.pyc diff --git a/ql/test/expression_evaluation/__pycache__/test_expression_evaluation.cpython-35.pyc b/ql/test/expression_evaluation/__pycache__/test_expression_evaluation.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..2104122 --- /dev/null +++ b/ql/test/expression_evaluation/__pycache__/test_expression_evaluation.cpython-35.pyc diff --git a/ql/test/expression_evaluation/test_expression_evaluation.py b/ql/test/expression_evaluation/test_expression_evaluation.py new file mode 100644 index 0000000..067ebda --- /dev/null +++ b/ql/test/expression_evaluation/test_expression_evaluation.py @@ -0,0 +1,49 @@ +from json import loads + +from ql.ast.extractors.extractor import extract_gui_model +from ql.ast.extractors.extractor import extract_identifier_types +from ql.ast.visitors.expression_evaluator import ExpressionEvaluator +from ql.ast.visitors.type_visitor import TypeVisitor +from ql.types.boolean import QLBoolean +from ql.types.date import QLDate +from ql.types.decimal import QLDecimal +from ql.types.integer import QLInteger +from ql.types.money import QLMoney +from ql.types.string import QLString +from ql.test.test import Test + + +class TestExpressionEvaluation(Test): + def __init__(self, directory, lexer, parser): + super(TestExpressionEvaluation, self).__init__('expression evaluation', directory) + self.__lexer = lexer + self.__parser = parser + + def test_file(self, file): + ast = self.__parser.parse(file, self.__lexer.lexer) + + if not self.__parser.errors: + TypeVisitor(extract_identifier_types(ast)).visit(ast) + model = extract_gui_model(ast) + result_type, result_value = file.split('\n')[0].split()[-2:] + correct_result = None + + if result_type == 'QLBoolean' and result_value == 'True': + correct_result = QLBoolean(True) + elif result_type == 'QLBoolean': + correct_result = QLBoolean() + elif result_type == 'QLDate': + day, month, year = loads(result_value) + correct_result = QLDate(day, month, year) + elif result_type == 'QLDecimal': + correct_result = QLDecimal(result_value) + elif result_type == 'QLInteger': + correct_result = QLInteger(result_value) + elif result_type == 'QLMoney': + correct_result = QLMoney(result_value) + elif result_type == 'QLString': + correct_result = QLString(result_value) + + expression_evaluator = ExpressionEvaluator(model) + expression_evaluator.visit(ast.block[0].answer) + return bool(expression_evaluator.result == correct_result) diff --git a/ql/test/expression_evaluation/valid/test001.ql b/ql/test/expression_evaluation/valid/test001.ql new file mode 100644 index 0000000..fc72525 --- /dev/null +++ b/ql/test/expression_evaluation/valid/test001.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean False +form label { + "Question" + id : boolean = False +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test002.ql b/ql/test/expression_evaluation/valid/test002.ql new file mode 100644 index 0000000..f4d722b --- /dev/null +++ b/ql/test/expression_evaluation/valid/test002.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean True +form label { + "Question" + id : boolean = True +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test003.ql b/ql/test/expression_evaluation/valid/test003.ql new file mode 100644 index 0000000..2998f36 --- /dev/null +++ b/ql/test/expression_evaluation/valid/test003.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean True +form label { + "Question" + id : boolean = not False +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test004.ql b/ql/test/expression_evaluation/valid/test004.ql new file mode 100644 index 0000000..fcfd827 --- /dev/null +++ b/ql/test/expression_evaluation/valid/test004.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean False +form label { + "Question" + id : boolean = not True +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test005.ql b/ql/test/expression_evaluation/valid/test005.ql new file mode 100644 index 0000000..0ee8989 --- /dev/null +++ b/ql/test/expression_evaluation/valid/test005.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean True +form label { + "Question" + id : boolean = False == False +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test006.ql b/ql/test/expression_evaluation/valid/test006.ql new file mode 100644 index 0000000..70f15f2 --- /dev/null +++ b/ql/test/expression_evaluation/valid/test006.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean False +form label { + "Question" + id : boolean = False == True +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test007.ql b/ql/test/expression_evaluation/valid/test007.ql new file mode 100644 index 0000000..76f37b0 --- /dev/null +++ b/ql/test/expression_evaluation/valid/test007.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean False +form label { + "Question" + id : boolean = True == False +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test008.ql b/ql/test/expression_evaluation/valid/test008.ql new file mode 100644 index 0000000..f6d5710 --- /dev/null +++ b/ql/test/expression_evaluation/valid/test008.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean True +form label { + "Question" + id : boolean = True == True +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test009.ql b/ql/test/expression_evaluation/valid/test009.ql new file mode 100644 index 0000000..6a3d465 --- /dev/null +++ b/ql/test/expression_evaluation/valid/test009.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean False +form label { + "Question" + id : boolean = False != False +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test010.ql b/ql/test/expression_evaluation/valid/test010.ql new file mode 100644 index 0000000..e398dde --- /dev/null +++ b/ql/test/expression_evaluation/valid/test010.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean True +form label { + "Question" + id : boolean = False != True +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test011.ql b/ql/test/expression_evaluation/valid/test011.ql new file mode 100644 index 0000000..3a7cbd1 --- /dev/null +++ b/ql/test/expression_evaluation/valid/test011.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean True +form label { + "Question" + id : boolean = True != False +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test012.ql b/ql/test/expression_evaluation/valid/test012.ql new file mode 100644 index 0000000..2a7185e --- /dev/null +++ b/ql/test/expression_evaluation/valid/test012.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean False +form label { + "Question" + id : boolean = True != True +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test013.ql b/ql/test/expression_evaluation/valid/test013.ql new file mode 100644 index 0000000..bed71a2 --- /dev/null +++ b/ql/test/expression_evaluation/valid/test013.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLDate [1,1,2018] +form label { + "Question" + id : boolean = date(1,1,2018) +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test014.ql b/ql/test/expression_evaluation/valid/test014.ql new file mode 100644 index 0000000..4d4413d --- /dev/null +++ b/ql/test/expression_evaluation/valid/test014.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean True +form label { + "Question" + id : boolean = date(1,1,2018) == date(1,1,2018) +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test015.ql b/ql/test/expression_evaluation/valid/test015.ql new file mode 100644 index 0000000..06a75ba --- /dev/null +++ b/ql/test/expression_evaluation/valid/test015.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean False +form label { + "Question" + id : boolean = date(1,1,2018) == date(1,1,2017) +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test016.ql b/ql/test/expression_evaluation/valid/test016.ql new file mode 100644 index 0000000..3cb4215 --- /dev/null +++ b/ql/test/expression_evaluation/valid/test016.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean False +form label { + "Question" + id : boolean = date(1,1,109) == date(1,1,2018) +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test017.ql b/ql/test/expression_evaluation/valid/test017.ql new file mode 100644 index 0000000..d4a3bbf --- /dev/null +++ b/ql/test/expression_evaluation/valid/test017.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean False +form label { + "Question" + id : boolean = date(1,1,2018) == date(1,7,2018) +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test018.ql b/ql/test/expression_evaluation/valid/test018.ql new file mode 100644 index 0000000..38f80ea --- /dev/null +++ b/ql/test/expression_evaluation/valid/test018.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean False +form label { + "Question" + id : boolean = date(1,3,2018) == date(1,1,2018) +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test019.ql b/ql/test/expression_evaluation/valid/test019.ql new file mode 100644 index 0000000..8d797b5 --- /dev/null +++ b/ql/test/expression_evaluation/valid/test019.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean False +form label { + "Question" + id : boolean = date(1,1,2018) == date(5,1,2018) +}
\ No newline at end of file diff --git a/ql/test/expression_evaluation/valid/test020.ql b/ql/test/expression_evaluation/valid/test020.ql new file mode 100644 index 0000000..5d401cf --- /dev/null +++ b/ql/test/expression_evaluation/valid/test020.ql @@ -0,0 +1,5 @@ +// Correct result type and result value: QLBoolean False +form label { + "Question" + id : boolean = date(21,1,2018) == date(1,1,2018) +}
\ No newline at end of file diff --git a/ql/test/lexing/__pycache__/test_lexing.cpython-35.pyc b/ql/test/lexing/__pycache__/test_lexing.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..eca2f01 --- /dev/null +++ b/ql/test/lexing/__pycache__/test_lexing.cpython-35.pyc diff --git a/ql/test/lexing/invalid/test001.ql b/ql/test/lexing/invalid/test001.ql new file mode 100644 index 0000000..37bf0fd --- /dev/null +++ b/ql/test/lexing/invalid/test001.ql @@ -0,0 +1,2 @@ +// Illegal character (`) +`
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test002.ql b/ql/test/lexing/invalid/test002.ql new file mode 100644 index 0000000..b691de9 --- /dev/null +++ b/ql/test/lexing/invalid/test002.ql @@ -0,0 +1,2 @@ +// Illegal character (~) +~
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test003.ql b/ql/test/lexing/invalid/test003.ql new file mode 100644 index 0000000..b75fc41 --- /dev/null +++ b/ql/test/lexing/invalid/test003.ql @@ -0,0 +1,2 @@ +// Illegal character (@) +@
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test004.ql b/ql/test/lexing/invalid/test004.ql new file mode 100644 index 0000000..9b3e1f7 --- /dev/null +++ b/ql/test/lexing/invalid/test004.ql @@ -0,0 +1,2 @@ +// Illegal character (#) +#
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test005.ql b/ql/test/lexing/invalid/test005.ql new file mode 100644 index 0000000..9bd5fc4 --- /dev/null +++ b/ql/test/lexing/invalid/test005.ql @@ -0,0 +1,2 @@ +// Illegal character (€) +€
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test006.ql b/ql/test/lexing/invalid/test006.ql new file mode 100644 index 0000000..a7c1336 --- /dev/null +++ b/ql/test/lexing/invalid/test006.ql @@ -0,0 +1,2 @@ +// Illegal character (%) +%
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test007.ql b/ql/test/lexing/invalid/test007.ql new file mode 100644 index 0000000..39cbd63 --- /dev/null +++ b/ql/test/lexing/invalid/test007.ql @@ -0,0 +1,2 @@ +// Illegal character (^) +^
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test008.ql b/ql/test/lexing/invalid/test008.ql new file mode 100644 index 0000000..82f2836 --- /dev/null +++ b/ql/test/lexing/invalid/test008.ql @@ -0,0 +1,2 @@ +// Illegal character (&) +&
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test009.ql b/ql/test/lexing/invalid/test009.ql new file mode 100644 index 0000000..e92526e --- /dev/null +++ b/ql/test/lexing/invalid/test009.ql @@ -0,0 +1,2 @@ +// Illegal character (_) +_
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test010.ql b/ql/test/lexing/invalid/test010.ql new file mode 100644 index 0000000..30c8837 --- /dev/null +++ b/ql/test/lexing/invalid/test010.ql @@ -0,0 +1,2 @@ +// Illegal character ([) +[
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test011.ql b/ql/test/lexing/invalid/test011.ql new file mode 100644 index 0000000..f047fbc --- /dev/null +++ b/ql/test/lexing/invalid/test011.ql @@ -0,0 +1,2 @@ +// Illegal character (]) +]
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test012.ql b/ql/test/lexing/invalid/test012.ql new file mode 100644 index 0000000..81e3796 --- /dev/null +++ b/ql/test/lexing/invalid/test012.ql @@ -0,0 +1,2 @@ +// Illegal character (\) +\
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test013.ql b/ql/test/lexing/invalid/test013.ql new file mode 100644 index 0000000..0a6d02c --- /dev/null +++ b/ql/test/lexing/invalid/test013.ql @@ -0,0 +1,2 @@ +// Illegal character (|) +|
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test014.ql b/ql/test/lexing/invalid/test014.ql new file mode 100644 index 0000000..48ede2c --- /dev/null +++ b/ql/test/lexing/invalid/test014.ql @@ -0,0 +1,2 @@ +// Illegal character (;) +;
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test015.ql b/ql/test/lexing/invalid/test015.ql new file mode 100644 index 0000000..ec798a0 --- /dev/null +++ b/ql/test/lexing/invalid/test015.ql @@ -0,0 +1,2 @@ +// Illegal character (') +'
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test016.ql b/ql/test/lexing/invalid/test016.ql new file mode 100644 index 0000000..6d67365 --- /dev/null +++ b/ql/test/lexing/invalid/test016.ql @@ -0,0 +1,2 @@ +// Illegal character (") +"
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test017.ql b/ql/test/lexing/invalid/test017.ql new file mode 100644 index 0000000..d8907bd --- /dev/null +++ b/ql/test/lexing/invalid/test017.ql @@ -0,0 +1,2 @@ +// Illegal character (,) +,
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test018.ql b/ql/test/lexing/invalid/test018.ql new file mode 100644 index 0000000..73fece7 --- /dev/null +++ b/ql/test/lexing/invalid/test018.ql @@ -0,0 +1,2 @@ +// Illegal character (?) +?
\ No newline at end of file diff --git a/ql/test/lexing/invalid/test019.ql b/ql/test/lexing/invalid/test019.ql new file mode 100644 index 0000000..407e52e --- /dev/null +++ b/ql/test/lexing/invalid/test019.ql @@ -0,0 +1,2 @@ +// Illegal characters (uppercase characters) +A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
\ No newline at end of file diff --git a/ql/test/lexing/test_lexing.py b/ql/test/lexing/test_lexing.py new file mode 100644 index 0000000..978b1d7 --- /dev/null +++ b/ql/test/lexing/test_lexing.py @@ -0,0 +1,15 @@ +from ql.test.test import Test + + +class TestLexing(Test): + def __init__(self, directory, lexer): + super(TestLexing, self).__init__('lexing', directory) + self.__lexer = lexer + + def test_file(self, file): + self.__lexer.tokenize(file) + + if self.__lexer.errors: + return False + + return True diff --git a/ql/test/lexing/valid/test001.ql b/ql/test/lexing/valid/test001.ql new file mode 100644 index 0000000..9862fb0 --- /dev/null +++ b/ql/test/lexing/valid/test001.ql @@ -0,0 +1,2 @@ +// Form token +form
\ No newline at end of file diff --git a/ql/test/lexing/valid/test002.ql b/ql/test/lexing/valid/test002.ql new file mode 100644 index 0000000..2efece0 --- /dev/null +++ b/ql/test/lexing/valid/test002.ql @@ -0,0 +1,2 @@ +// If token +if
\ No newline at end of file diff --git a/ql/test/lexing/valid/test003.ql b/ql/test/lexing/valid/test003.ql new file mode 100644 index 0000000..dc30033 --- /dev/null +++ b/ql/test/lexing/valid/test003.ql @@ -0,0 +1,2 @@ +// Boolean type token +boolean
\ No newline at end of file diff --git a/ql/test/lexing/valid/test004.ql b/ql/test/lexing/valid/test004.ql new file mode 100644 index 0000000..233e652 --- /dev/null +++ b/ql/test/lexing/valid/test004.ql @@ -0,0 +1,2 @@ +// Date type token +date
\ No newline at end of file diff --git a/ql/test/lexing/valid/test005.ql b/ql/test/lexing/valid/test005.ql new file mode 100644 index 0000000..9d1f615 --- /dev/null +++ b/ql/test/lexing/valid/test005.ql @@ -0,0 +1,2 @@ +// Decimal type token +decimal
\ No newline at end of file diff --git a/ql/test/lexing/valid/test006.ql b/ql/test/lexing/valid/test006.ql new file mode 100644 index 0000000..506c72e --- /dev/null +++ b/ql/test/lexing/valid/test006.ql @@ -0,0 +1,2 @@ +// Integer type token +integer
\ No newline at end of file diff --git a/ql/test/lexing/valid/test007.ql b/ql/test/lexing/valid/test007.ql new file mode 100644 index 0000000..66c665f --- /dev/null +++ b/ql/test/lexing/valid/test007.ql @@ -0,0 +1,2 @@ +// Money type token +money
\ No newline at end of file diff --git a/ql/test/lexing/valid/test008.ql b/ql/test/lexing/valid/test008.ql new file mode 100644 index 0000000..3455595 --- /dev/null +++ b/ql/test/lexing/valid/test008.ql @@ -0,0 +1,2 @@ +// String type token +string
\ No newline at end of file diff --git a/ql/test/lexing/valid/test009.ql b/ql/test/lexing/valid/test009.ql new file mode 100644 index 0000000..123a526 --- /dev/null +++ b/ql/test/lexing/valid/test009.ql @@ -0,0 +1,2 @@ +// Plus token ++
\ No newline at end of file diff --git a/ql/test/lexing/valid/test010.ql b/ql/test/lexing/valid/test010.ql new file mode 100644 index 0000000..ac494f7 --- /dev/null +++ b/ql/test/lexing/valid/test010.ql @@ -0,0 +1,2 @@ +// Minus token +-
\ No newline at end of file diff --git a/ql/test/lexing/valid/test011.ql b/ql/test/lexing/valid/test011.ql new file mode 100644 index 0000000..c53f248 --- /dev/null +++ b/ql/test/lexing/valid/test011.ql @@ -0,0 +1,2 @@ +// Times token +*
\ No newline at end of file diff --git a/ql/test/lexing/valid/test012.ql b/ql/test/lexing/valid/test012.ql new file mode 100644 index 0000000..195d9b9 --- /dev/null +++ b/ql/test/lexing/valid/test012.ql @@ -0,0 +1,2 @@ +// Divide token +/
\ No newline at end of file diff --git a/ql/test/lexing/valid/test013.ql b/ql/test/lexing/valid/test013.ql new file mode 100644 index 0000000..d1c0471 --- /dev/null +++ b/ql/test/lexing/valid/test013.ql @@ -0,0 +1,2 @@ +// Colon token +:
\ No newline at end of file diff --git a/ql/test/lexing/valid/test014.ql b/ql/test/lexing/valid/test014.ql new file mode 100644 index 0000000..f72179a --- /dev/null +++ b/ql/test/lexing/valid/test014.ql @@ -0,0 +1,2 @@ +// Assign token +=
\ No newline at end of file diff --git a/ql/test/lexing/valid/test015.ql b/ql/test/lexing/valid/test015.ql new file mode 100644 index 0000000..09f1ea1 --- /dev/null +++ b/ql/test/lexing/valid/test015.ql @@ -0,0 +1,2 @@ +// Equals token +==
\ No newline at end of file diff --git a/ql/test/lexing/valid/test016.ql b/ql/test/lexing/valid/test016.ql new file mode 100644 index 0000000..9cc8e9b --- /dev/null +++ b/ql/test/lexing/valid/test016.ql @@ -0,0 +1,2 @@ +// Not equals token +!=
\ No newline at end of file diff --git a/ql/test/lexing/valid/test017.ql b/ql/test/lexing/valid/test017.ql new file mode 100644 index 0000000..ce8af09 --- /dev/null +++ b/ql/test/lexing/valid/test017.ql @@ -0,0 +1,2 @@ +// Greater than token +>
\ No newline at end of file diff --git a/ql/test/lexing/valid/test018.ql b/ql/test/lexing/valid/test018.ql new file mode 100644 index 0000000..dad4f9c --- /dev/null +++ b/ql/test/lexing/valid/test018.ql @@ -0,0 +1,2 @@ +// Greater equals token +>=
\ No newline at end of file diff --git a/ql/test/lexing/valid/test019.ql b/ql/test/lexing/valid/test019.ql new file mode 100644 index 0000000..39ec8a3 --- /dev/null +++ b/ql/test/lexing/valid/test019.ql @@ -0,0 +1,2 @@ +// Less than token +<
\ No newline at end of file diff --git a/ql/test/lexing/valid/test020.ql b/ql/test/lexing/valid/test020.ql new file mode 100644 index 0000000..902ec15 --- /dev/null +++ b/ql/test/lexing/valid/test020.ql @@ -0,0 +1,2 @@ +// Less equals token +<=
\ No newline at end of file diff --git a/ql/test/lexing/valid/test021.ql b/ql/test/lexing/valid/test021.ql new file mode 100644 index 0000000..296f504 --- /dev/null +++ b/ql/test/lexing/valid/test021.ql @@ -0,0 +1,2 @@ +// Not token +not
\ No newline at end of file diff --git a/ql/test/lexing/valid/test022.ql b/ql/test/lexing/valid/test022.ql new file mode 100644 index 0000000..1d4fe36 --- /dev/null +++ b/ql/test/lexing/valid/test022.ql @@ -0,0 +1,2 @@ +// Brace tokens +{}
\ No newline at end of file diff --git a/ql/test/lexing/valid/test023.ql b/ql/test/lexing/valid/test023.ql new file mode 100644 index 0000000..3b27a60 --- /dev/null +++ b/ql/test/lexing/valid/test023.ql @@ -0,0 +1,2 @@ +// Bracket tokens +()
\ No newline at end of file diff --git a/ql/test/lexing/valid/test024.ql b/ql/test/lexing/valid/test024.ql new file mode 100644 index 0000000..72854c9 --- /dev/null +++ b/ql/test/lexing/valid/test024.ql @@ -0,0 +1,2 @@ +// Whitespace tokens + diff --git a/ql/test/lexing/valid/test025.ql b/ql/test/lexing/valid/test025.ql new file mode 100644 index 0000000..ceb93d0 --- /dev/null +++ b/ql/test/lexing/valid/test025.ql @@ -0,0 +1,2 @@ +// Identifier token (lowercase) +testidentifier
\ No newline at end of file diff --git a/ql/test/lexing/valid/test026.ql b/ql/test/lexing/valid/test026.ql new file mode 100644 index 0000000..90589b2 --- /dev/null +++ b/ql/test/lexing/valid/test026.ql @@ -0,0 +1,2 @@ +// Identifier token (camelcase) +testIdentifier
\ No newline at end of file diff --git a/ql/test/lexing/valid/test027.ql b/ql/test/lexing/valid/test027.ql new file mode 100644 index 0000000..076f4b0 --- /dev/null +++ b/ql/test/lexing/valid/test027.ql @@ -0,0 +1,2 @@ +// Identifier token (underscore) +test_identifier
\ No newline at end of file diff --git a/ql/test/lexing/valid/test028.ql b/ql/test/lexing/valid/test028.ql new file mode 100644 index 0000000..855dd9a --- /dev/null +++ b/ql/test/lexing/valid/test028.ql @@ -0,0 +1,2 @@ +// Identifier token (number) +identifier123
\ No newline at end of file diff --git a/ql/test/lexing/valid/test029.ql b/ql/test/lexing/valid/test029.ql new file mode 100644 index 0000000..1d37fa2 --- /dev/null +++ b/ql/test/lexing/valid/test029.ql @@ -0,0 +1,2 @@ +// Boolean literal token (false) +False
\ No newline at end of file diff --git a/ql/test/lexing/valid/test030.ql b/ql/test/lexing/valid/test030.ql new file mode 100644 index 0000000..bc70591 --- /dev/null +++ b/ql/test/lexing/valid/test030.ql @@ -0,0 +1,2 @@ +// Boolean literal token (true) +True
\ No newline at end of file diff --git a/ql/test/lexing/valid/test031.ql b/ql/test/lexing/valid/test031.ql new file mode 100644 index 0000000..106a0ad --- /dev/null +++ b/ql/test/lexing/valid/test031.ql @@ -0,0 +1,2 @@ +// Date literal token +date(1, 1, 2018)
\ No newline at end of file diff --git a/ql/test/lexing/valid/test032.ql b/ql/test/lexing/valid/test032.ql new file mode 100644 index 0000000..51cc57a --- /dev/null +++ b/ql/test/lexing/valid/test032.ql @@ -0,0 +1,2 @@ +// Date literal token +date(99, 99, 9999)
\ No newline at end of file diff --git a/ql/test/lexing/valid/test033.ql b/ql/test/lexing/valid/test033.ql new file mode 100644 index 0000000..f6a8535 --- /dev/null +++ b/ql/test/lexing/valid/test033.ql @@ -0,0 +1,2 @@ +// Decimal literal token +0.0
\ No newline at end of file diff --git a/ql/test/lexing/valid/test034.ql b/ql/test/lexing/valid/test034.ql new file mode 100644 index 0000000..15b2e6a --- /dev/null +++ b/ql/test/lexing/valid/test034.ql @@ -0,0 +1,2 @@ +// Decimal literal token +3.14
\ No newline at end of file diff --git a/ql/test/lexing/valid/test035.ql b/ql/test/lexing/valid/test035.ql new file mode 100644 index 0000000..49616a7 --- /dev/null +++ b/ql/test/lexing/valid/test035.ql @@ -0,0 +1,2 @@ +// Decimal literal token +1234567890.0987654321
\ No newline at end of file diff --git a/ql/test/lexing/valid/test036.ql b/ql/test/lexing/valid/test036.ql new file mode 100644 index 0000000..86f7a4e --- /dev/null +++ b/ql/test/lexing/valid/test036.ql @@ -0,0 +1,2 @@ +// Decimal literal token +999999999999999999999999999999999999999999999999999999999999999.999999999999999999999999999999999999999999999999999999999999999
\ No newline at end of file diff --git a/ql/test/lexing/valid/test037.ql b/ql/test/lexing/valid/test037.ql new file mode 100644 index 0000000..174d0ce --- /dev/null +++ b/ql/test/lexing/valid/test037.ql @@ -0,0 +1,2 @@ +// Integer literal token +0
\ No newline at end of file diff --git a/ql/test/lexing/valid/test038.ql b/ql/test/lexing/valid/test038.ql new file mode 100644 index 0000000..6740489 --- /dev/null +++ b/ql/test/lexing/valid/test038.ql @@ -0,0 +1,2 @@ +// Integer literal token +1234567890
\ No newline at end of file diff --git a/ql/test/lexing/valid/test039.ql b/ql/test/lexing/valid/test039.ql new file mode 100644 index 0000000..d2dbc53 --- /dev/null +++ b/ql/test/lexing/valid/test039.ql @@ -0,0 +1,2 @@ +// String literal token +"abcdefghijklmnopqrstuvwxyz"
\ No newline at end of file diff --git a/ql/test/lexing/valid/test040.ql b/ql/test/lexing/valid/test040.ql new file mode 100644 index 0000000..306582b --- /dev/null +++ b/ql/test/lexing/valid/test040.ql @@ -0,0 +1,2 @@ +// String literal token +"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
\ No newline at end of file diff --git a/ql/test/lexing/valid/test041.ql b/ql/test/lexing/valid/test041.ql new file mode 100644 index 0000000..84f0aff --- /dev/null +++ b/ql/test/lexing/valid/test041.ql @@ -0,0 +1,2 @@ +// String literal token +"1234567890"
\ No newline at end of file diff --git a/ql/test/lexing/valid/test042.ql b/ql/test/lexing/valid/test042.ql new file mode 100644 index 0000000..d389d9f --- /dev/null +++ b/ql/test/lexing/valid/test042.ql @@ -0,0 +1,2 @@ +// String literal token +"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
\ No newline at end of file diff --git a/ql/test/lexing/valid/test043.ql b/ql/test/lexing/valid/test043.ql new file mode 100644 index 0000000..6698694 --- /dev/null +++ b/ql/test/lexing/valid/test043.ql @@ -0,0 +1,2 @@ +// String literal token +"`~!@#$%*()-=_+[]\{}|;:,./<>?"
\ No newline at end of file diff --git a/ql/test/lexing/valid/test044.ql b/ql/test/lexing/valid/test044.ql new file mode 100644 index 0000000..d09b55d --- /dev/null +++ b/ql/test/lexing/valid/test044.ql @@ -0,0 +1,2 @@ +// String literal token +"\'"
\ No newline at end of file diff --git a/ql/test/lexing/valid/test045.ql b/ql/test/lexing/valid/test045.ql new file mode 100644 index 0000000..d85d414 --- /dev/null +++ b/ql/test/lexing/valid/test045.ql @@ -0,0 +1,2 @@ +// String literal token +"\""
\ No newline at end of file diff --git a/ql/test/parsing/__pycache__/test_parsing.cpython-35.pyc b/ql/test/parsing/__pycache__/test_parsing.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..4e89c3e --- /dev/null +++ b/ql/test/parsing/__pycache__/test_parsing.cpython-35.pyc diff --git a/ql/test/parsing/invalid/test001.ql b/ql/test/parsing/invalid/test001.ql new file mode 100644 index 0000000..fab17ac --- /dev/null +++ b/ql/test/parsing/invalid/test001.ql @@ -0,0 +1 @@ +// Empty file diff --git a/ql/test/parsing/invalid/test002.ql b/ql/test/parsing/invalid/test002.ql new file mode 100644 index 0000000..d84f901 --- /dev/null +++ b/ql/test/parsing/invalid/test002.ql @@ -0,0 +1,3 @@ +// Empty form without label +form { +}
\ No newline at end of file diff --git a/ql/test/parsing/invalid/test003.ql b/ql/test/parsing/invalid/test003.ql new file mode 100644 index 0000000..57975a1 --- /dev/null +++ b/ql/test/parsing/invalid/test003.ql @@ -0,0 +1,3 @@ +// Empty form +form testForm { +}
\ No newline at end of file diff --git a/ql/test/parsing/invalid/test004.ql b/ql/test/parsing/invalid/test004.ql new file mode 100644 index 0000000..6f2fb9f --- /dev/null +++ b/ql/test/parsing/invalid/test004.ql @@ -0,0 +1,5 @@ +// Form without label +form { + "Question?" + var : boolean +}
\ No newline at end of file diff --git a/ql/test/parsing/invalid/test005.ql b/ql/test/parsing/invalid/test005.ql new file mode 100644 index 0000000..5b67d6e --- /dev/null +++ b/ql/test/parsing/invalid/test005.ql @@ -0,0 +1,5 @@ +// Question label without quotation marks +form testForm { + question + var : cows +}
\ No newline at end of file diff --git a/ql/test/parsing/invalid/test006.ql b/ql/test/parsing/invalid/test006.ql new file mode 100644 index 0000000..b902dc9 --- /dev/null +++ b/ql/test/parsing/invalid/test006.ql @@ -0,0 +1,5 @@ +// Question with invalid type +form testForm { + "Question?" + var : cows +}
\ No newline at end of file diff --git a/ql/test/parsing/invalid/test007.ql b/ql/test/parsing/invalid/test007.ql new file mode 100644 index 0000000..e16685e --- /dev/null +++ b/ql/test/parsing/invalid/test007.ql @@ -0,0 +1,5 @@ +// Question identifier with quotation marks +form testForm { + "Question?" + "var" : boolean +}
\ No newline at end of file diff --git a/ql/test/parsing/invalid/test018.ql b/ql/test/parsing/invalid/test018.ql new file mode 100644 index 0000000..80deece --- /dev/null +++ b/ql/test/parsing/invalid/test018.ql @@ -0,0 +1,7 @@ +// Empty if conditional +form testForm { + if () { + "Question?" + id : boolean + } +}
\ No newline at end of file diff --git a/ql/test/parsing/invalid/test019.ql b/ql/test/parsing/invalid/test019.ql new file mode 100644 index 0000000..1bde8f1 --- /dev/null +++ b/ql/test/parsing/invalid/test019.ql @@ -0,0 +1,5 @@ +// Empty if block +form label { + if (1 == 2) { + } +}
\ No newline at end of file diff --git a/ql/test/parsing/test_parsing.py b/ql/test/parsing/test_parsing.py new file mode 100644 index 0000000..86900f9 --- /dev/null +++ b/ql/test/parsing/test_parsing.py @@ -0,0 +1,16 @@ +from ql.test.test import Test + + +class TestParsing(Test): + def __init__(self, directory, lexer, parser): + super(TestParsing, self).__init__('parsing', directory) + self.__lexer = lexer + self.__parser = parser + + def test_file(self, file): + self.__parser.parse(file, self.__lexer.lexer) + + if self.__parser.errors: + return False + + return True diff --git a/ql/test/parsing/valid/test001.ql b/ql/test/parsing/valid/test001.ql new file mode 100644 index 0000000..aecb488 --- /dev/null +++ b/ql/test/parsing/valid/test001.ql @@ -0,0 +1,5 @@ +// Form with question type boolean +form testForm { + "Question?" + var: boolean +}
\ No newline at end of file diff --git a/ql/test/parsing/valid/test002.ql b/ql/test/parsing/valid/test002.ql new file mode 100644 index 0000000..89402fa --- /dev/null +++ b/ql/test/parsing/valid/test002.ql @@ -0,0 +1,5 @@ +// Form with question of type date +form testForm { + "Question?" + var: date +}
\ No newline at end of file diff --git a/ql/test/parsing/valid/test003.ql b/ql/test/parsing/valid/test003.ql new file mode 100644 index 0000000..8f8f448 --- /dev/null +++ b/ql/test/parsing/valid/test003.ql @@ -0,0 +1,5 @@ +// Form with question of type decimal +form testForm { + "Question?" + var: decimal +}
\ No newline at end of file diff --git a/ql/test/parsing/valid/test004.ql b/ql/test/parsing/valid/test004.ql new file mode 100644 index 0000000..7d4b77b --- /dev/null +++ b/ql/test/parsing/valid/test004.ql @@ -0,0 +1,5 @@ +// Form with question of type integer +form testForm { + "Question?" + var: integer +}
\ No newline at end of file diff --git a/ql/test/parsing/valid/test005.ql b/ql/test/parsing/valid/test005.ql new file mode 100644 index 0000000..eafc6c1 --- /dev/null +++ b/ql/test/parsing/valid/test005.ql @@ -0,0 +1,5 @@ +// Form with question of type money +form testForm { + "Question?" + var: money +}
\ No newline at end of file diff --git a/ql/test/parsing/valid/test006.ql b/ql/test/parsing/valid/test006.ql new file mode 100644 index 0000000..16efa4d --- /dev/null +++ b/ql/test/parsing/valid/test006.ql @@ -0,0 +1,5 @@ +// Form with question of type string +form testForm { + "Question?" + var: string +}
\ No newline at end of file diff --git a/ql/test/parsing/valid/test007.ql b/ql/test/parsing/valid/test007.ql new file mode 100644 index 0000000..dd2b47a --- /dev/null +++ b/ql/test/parsing/valid/test007.ql @@ -0,0 +1,8 @@ +// Form with two questions with the same identifier +form testForm { + "Question?" + var: boolean + + "Question?" + var: boolean +} diff --git a/ql/test/parsing/valid/test008.ql b/ql/test/parsing/valid/test008.ql new file mode 100644 index 0000000..20cb866 --- /dev/null +++ b/ql/test/parsing/valid/test008.ql @@ -0,0 +1,8 @@ +// Form with two questions with different identifiers +form testForm { + "Question?" + var1: boolean + + "Question?" + var2: boolean +} diff --git a/ql/test/parsing/valid/test009.ql b/ql/test/parsing/valid/test009.ql new file mode 100644 index 0000000..a4edfa1 --- /dev/null +++ b/ql/test/parsing/valid/test009.ql @@ -0,0 +1,20 @@ +// Form with questions of all supported types +form testForm { + "Question?" + var1: boolean + + "Question?" + var2: date + + "Question?" + var3: decimal + + "Question?" + var4: integer + + "Question?" + var5: money + + "Question?" + var6: string +} diff --git a/ql/test/parsing/valid/test010.ql b/ql/test/parsing/valid/test010.ql new file mode 100644 index 0000000..c1985f8 --- /dev/null +++ b/ql/test/parsing/valid/test010.ql @@ -0,0 +1,5 @@ +// Form with computed question +form testForm { + "Question?" + var: boolean = True +}
\ No newline at end of file diff --git a/ql/test/parsing/valid/test011.ql b/ql/test/parsing/valid/test011.ql new file mode 100644 index 0000000..a59cae6 --- /dev/null +++ b/ql/test/parsing/valid/test011.ql @@ -0,0 +1,5 @@ +// Form with computed question +form testForm { + "Question?" + var: boolean = False +}
\ No newline at end of file diff --git a/ql/test/parsing/valid/test012.ql b/ql/test/parsing/valid/test012.ql new file mode 100644 index 0000000..d745fba --- /dev/null +++ b/ql/test/parsing/valid/test012.ql @@ -0,0 +1,5 @@ +// Form with computed question +form testForm { + "Question?" + var: boolean = "ADSADsad" +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/__pycache__/test_semantic_analysis.cpython-35.pyc b/ql/test/semantic_analysis/__pycache__/test_semantic_analysis.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..5b92465 --- /dev/null +++ b/ql/test/semantic_analysis/__pycache__/test_semantic_analysis.cpython-35.pyc diff --git a/ql/test/semantic_analysis/invalid/test001.ql b/ql/test/semantic_analysis/invalid/test001.ql new file mode 100644 index 0000000..42b1b41 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test001.ql @@ -0,0 +1,9 @@ +// Reference to unknown identifier in condition +form testForm { + if (unknownIdentifier) { + "First Question" + anotherIdentifier : integer + } + "Second Question" + testIdentifier : boolean +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test002.ql b/ql/test/semantic_analysis/invalid/test002.ql new file mode 100644 index 0000000..856447d --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test002.ql @@ -0,0 +1,9 @@ +// Reference to unknown identifier in computed question +form testForm { + "First Question" + testIdentifier : integer + "Second Question" + anotherIdentifier : integer = testIdentifier + unknownIdentifier +} + + diff --git a/ql/test/semantic_analysis/invalid/test003.ql b/ql/test/semantic_analysis/invalid/test003.ql new file mode 100644 index 0000000..1491a85 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test003.ql @@ -0,0 +1,13 @@ +// Reference to identifier in condition out of scope +form testForm { + "First Question" + testIdentifier : boolean + if (testIdentifier) { + "Second Question" + anotherIdentifier : integer + } + if (anotherIdentifier) { + "Unreachable Question" + unreachableIdentifier : integer + } +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test004.ql b/ql/test/semantic_analysis/invalid/test004.ql new file mode 100644 index 0000000..5ae3e94 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test004.ql @@ -0,0 +1,11 @@ +// Reference to identifier in computed question out of scope +form testForm { + "First Question" + testIdentifier : boolean + if (testIdentifier) { + "Second Question" + anotherIdentifier : integer + } + "Third Question" + unknownIdentifier : integer = anotherIdentifier + 1 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test005.ql b/ql/test/semantic_analysis/invalid/test005.ql new file mode 100644 index 0000000..de066f2 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test005.ql @@ -0,0 +1,5 @@ +// Identifier dependent on itself (reflexive) +form testForm { + "First Question" + firstIdentifier : integer = firstIdentifier + 1 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test006.ql b/ql/test/semantic_analysis/invalid/test006.ql new file mode 100644 index 0000000..12cf8f0 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test006.ql @@ -0,0 +1,7 @@ +// Identifiers dependent on each other (symmetric) +form testForm { + "First Question" + firstIdentifier : integer = secondIdentifier + 1 + "Second Question" + secondIdentifier : integer = firstIdentifier + 1 +} diff --git a/ql/test/semantic_analysis/invalid/test007.ql b/ql/test/semantic_analysis/invalid/test007.ql new file mode 100644 index 0000000..08f4f5f --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test007.ql @@ -0,0 +1,9 @@ +// Identifiers dependent on each other (transitive) +form testForm { + "First Question" + firstIdentifier : integer = secondIdentifier + 1 + "Second Question" + secondIdentifier : integer = thirdIdentifier + 1 + "Third Question" + thirdIdentifier : integer = firstIdentifier + 1 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test008.ql b/ql/test/semantic_analysis/invalid/test008.ql new file mode 100644 index 0000000..6c8a660 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test008.ql @@ -0,0 +1,7 @@ +// Different questions with equal identifier +form testForm { + "First Question" + someIdentifier : integer + "Second Question" + someIdentifier : decimal +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test009.ql b/ql/test/semantic_analysis/invalid/test009.ql new file mode 100644 index 0000000..362a2b1 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test009.ql @@ -0,0 +1,7 @@ +// Equal questions with different types +form testForm { + "First Question" + someIdentifier : integer + "First Question" + someIdentifier : decimal +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test010.ql b/ql/test/semantic_analysis/invalid/test010.ql new file mode 100644 index 0000000..30a03e2 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test010.ql @@ -0,0 +1,5 @@ +// Incompatible types for addition operation +form testForm { + "First Question" + someIdentifier : decimal = 10.0 + True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test011.ql b/ql/test/semantic_analysis/invalid/test011.ql new file mode 100644 index 0000000..de59f13 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test011.ql @@ -0,0 +1,5 @@ +// Incompatible types for subtraction operation +form testForm { + "First Question" + someIdentifier : decimal = 10.0 - True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test012.ql b/ql/test/semantic_analysis/invalid/test012.ql new file mode 100644 index 0000000..006bd0c --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test012.ql @@ -0,0 +1,5 @@ +// Incompatible types for greater equals operation +form testForm { + "First Question" + someIdentifier : boolean = 10.0 >= True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test013.ql b/ql/test/semantic_analysis/invalid/test013.ql new file mode 100644 index 0000000..2896f80 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test013.ql @@ -0,0 +1,5 @@ +// Incompatible types for greater than operation +form testForm { + "First Question" + someIdentifier : boolean = 10.0 > True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test014.ql b/ql/test/semantic_analysis/invalid/test014.ql new file mode 100644 index 0000000..b5b7774 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test014.ql @@ -0,0 +1,5 @@ +// Incompatible types for less equals operation +form testForm { + "First Question" + someIdentifier : boolean = 10.0 <= True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test015.ql b/ql/test/semantic_analysis/invalid/test015.ql new file mode 100644 index 0000000..6c52b37 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test015.ql @@ -0,0 +1,5 @@ +// Incompatible types for less than operation +form testForm { + "First Question" + someIdentifier : boolean = 10.0 < True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test016.ql b/ql/test/semantic_analysis/invalid/test016.ql new file mode 100644 index 0000000..dcf98ea --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test016.ql @@ -0,0 +1,5 @@ +// Incompatible types for and operation +form testForm { + "First Question" + someIdentifier : boolean = 10.0 && True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test017.ql b/ql/test/semantic_analysis/invalid/test017.ql new file mode 100644 index 0000000..9eef105 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test017.ql @@ -0,0 +1,5 @@ +// Incompatible types for or operation +form testForm { + "First Question" + someIdentifier : boolean = 10.0 || True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test018.ql b/ql/test/semantic_analysis/invalid/test018.ql new file mode 100644 index 0000000..bd18cf9 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test018.ql @@ -0,0 +1,5 @@ +// Incompatible types for multiplication operation +form testForm { + "First Question" + someIdentifier : decimal = 10.0 * True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test019.ql b/ql/test/semantic_analysis/invalid/test019.ql new file mode 100644 index 0000000..69a2c38 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test019.ql @@ -0,0 +1,5 @@ +// Incompatible types for division operation +form testForm { + "First Question" + someIdentifier : decimal = 10.0 / True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test020.ql b/ql/test/semantic_analysis/invalid/test020.ql new file mode 100644 index 0000000..538bdf9 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test020.ql @@ -0,0 +1,5 @@ +// Incompatible result type for addition operation +form testForm { + "First Question" + someIdentifier : integer = 10.1 + 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test021.ql b/ql/test/semantic_analysis/invalid/test021.ql new file mode 100644 index 0000000..74e596d --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test021.ql @@ -0,0 +1,5 @@ +// Incompatible result type for subtraction operation +form testForm { + "First Question" + someIdentifier : integer = 10.1 - 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test022.ql b/ql/test/semantic_analysis/invalid/test022.ql new file mode 100644 index 0000000..9cf774a --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test022.ql @@ -0,0 +1,5 @@ +// Incompatible result type for greater equals operation +form testForm { + "First Question" + someIdentifier : integer = 10.0 >= 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test023.ql b/ql/test/semantic_analysis/invalid/test023.ql new file mode 100644 index 0000000..f7d674b --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test023.ql @@ -0,0 +1,5 @@ +// Incompatible result type for greater than operation +form testForm { + "First Question" + someIdentifier : integer = 10.0 > 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test024.ql b/ql/test/semantic_analysis/invalid/test024.ql new file mode 100644 index 0000000..f262f5c --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test024.ql @@ -0,0 +1,5 @@ +// Incompatible result type for less equals operation +form testForm { + "First Question" + someIdentifier : integer = 10.0 <= 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test025.ql b/ql/test/semantic_analysis/invalid/test025.ql new file mode 100644 index 0000000..ef823b5 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test025.ql @@ -0,0 +1,5 @@ +// Incompatible result type for less than operation +form testForm { + "First Question" + someIdentifier : integer = 10.0 < 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test026.ql b/ql/test/semantic_analysis/invalid/test026.ql new file mode 100644 index 0000000..b1e8a5b --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test026.ql @@ -0,0 +1,5 @@ +// Incompatible result type for and operation +form testForm { + "First Question" + someIdentifier : integer = True && True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test027.ql b/ql/test/semantic_analysis/invalid/test027.ql new file mode 100644 index 0000000..262aa0e --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test027.ql @@ -0,0 +1,5 @@ +// Incompatible result type for or operation +form testForm { + "First Question" + someIdentifier : integer = False || True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test028.ql b/ql/test/semantic_analysis/invalid/test028.ql new file mode 100644 index 0000000..ea02ccd --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test028.ql @@ -0,0 +1,5 @@ +// Incompatible result type for multiplication operation +form testForm { + "First Question" + someIdentifier : integer = 10.1 * 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test029.ql b/ql/test/semantic_analysis/invalid/test029.ql new file mode 100644 index 0000000..23f3c78 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test029.ql @@ -0,0 +1,5 @@ +// Incompatible result type for division operation +form testForm { + "First Question" + someIdentifier : integer = 10.1 / 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test030.ql b/ql/test/semantic_analysis/invalid/test030.ql new file mode 100644 index 0000000..3de208c --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test030.ql @@ -0,0 +1,7 @@ +// Complex condition with incompatible types +form testForm { + if ((15.5 >= 15) && ((3.0 * True) - 15 > -10 / 2)) { + "First Question" + someIdentifier : integer + } +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test031.ql b/ql/test/semantic_analysis/invalid/test031.ql new file mode 100644 index 0000000..0d6f75c --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test031.ql @@ -0,0 +1,5 @@ +// Complex computed question with incompatible types +form testForm { + "First Question" + someIdentifier : boolean = (25.5 >= True) && ((10.0 / 3) - 15 < -10 * 2) +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/invalid/test032.ql b/ql/test/semantic_analysis/invalid/test032.ql new file mode 100644 index 0000000..9de5ff2 --- /dev/null +++ b/ql/test/semantic_analysis/invalid/test032.ql @@ -0,0 +1,5 @@ +// Complex computed question with incompatible result type +form testForm { + "First Question" + someIdentifier : integer = (25.5 >= 10) && ((10.0 / 3) - 15 < -10 * 2) +} diff --git a/ql/test/semantic_analysis/test_semantic_analysis.py b/ql/test/semantic_analysis/test_semantic_analysis.py new file mode 100644 index 0000000..ca01231 --- /dev/null +++ b/ql/test/semantic_analysis/test_semantic_analysis.py @@ -0,0 +1,39 @@ +from ql.ast.checkers.dependency_checker import DependencyChecker +from ql.ast.checkers.question_checker import QuestionChecker +from ql.ast.checkers.reference_checker import ReferenceChecker +from ql.ast.extractors.extractor import extract_identifier_dependencies +from ql.ast.extractors.extractor import extract_identifier_scopes +from ql.ast.extractors.extractor import extract_identifier_types +from ql.ast.extractors.extractor import extract_questions +from ql.ast.visitors.type_visitor import TypeVisitor +from ql.test.test import Test + + +class TestSemanticAnalysis(Test): + def __init__(self, directory, lexer, parser): + super(TestSemanticAnalysis, self).__init__('semantic analysis', directory) + self.__lexer = lexer + self.__parser = parser + + def test_file(self, file): + ast = self.__parser.parse(file, self.__lexer.lexer) + + reference_errors = ReferenceChecker(extract_identifier_scopes(ast)).errors + if reference_errors: + return False + + dependency_errors = DependencyChecker(extract_identifier_dependencies(ast)).errors + if dependency_errors: + return False + + question_errors = QuestionChecker(extract_questions(ast)).errors + if question_errors: + return False + + type_visitor = TypeVisitor(extract_identifier_types(ast)) + type_visitor.visit(ast) + type_errors = type_visitor.errors + if type_errors: + return False + + return True diff --git a/ql/test/semantic_analysis/valid/test001.ql b/ql/test/semantic_analysis/valid/test001.ql new file mode 100644 index 0000000..d9d037f --- /dev/null +++ b/ql/test/semantic_analysis/valid/test001.ql @@ -0,0 +1,9 @@ +// Identifier reference in condition +form testForm { + "First Question" + testIdentifier : boolean + if (testIdentifier) { + "Second Question" + anotherIdentifier : integer + } +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test002.ql b/ql/test/semantic_analysis/valid/test002.ql new file mode 100644 index 0000000..afe1f5c --- /dev/null +++ b/ql/test/semantic_analysis/valid/test002.ql @@ -0,0 +1,7 @@ +// Identifier reference in computed question +form testForm { + "First Question" + testIdentifier : integer + "Second Question" + anotherIdentifier : integer = testIdentifier +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test003.ql b/ql/test/semantic_analysis/valid/test003.ql new file mode 100644 index 0000000..b89d0c1 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test003.ql @@ -0,0 +1,9 @@ +// Identifier declared after reference in condition +form testForm { + if (testIdentifier) { + "First Question" + anotherIdentifier : integer + } + "Second Question" + testIdentifier : boolean +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test004.ql b/ql/test/semantic_analysis/valid/test004.ql new file mode 100644 index 0000000..8f4feb0 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test004.ql @@ -0,0 +1,7 @@ +// Identifier declared after reference in computed question +form testForm { + "First Question" + anotherIdentifier : integer = testIdentifier + 1 + "Second Question" + testIdentifier : integer +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test005.ql b/ql/test/semantic_analysis/valid/test005.ql new file mode 100644 index 0000000..8620dc9 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test005.ql @@ -0,0 +1,15 @@ +// Identifier reference in nested condition +form testForm { + "First Question" + firstCondition : boolean + "Second Question" + secondCondition : boolean + if (firstCondition) { + "Third Question" + anotherIdentifier : integer + if (secondCondition) { + "Fourth Question" + yetAnotherIdentifier : decimal + } + } +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test006.ql b/ql/test/semantic_analysis/valid/test006.ql new file mode 100644 index 0000000..855332e --- /dev/null +++ b/ql/test/semantic_analysis/valid/test006.ql @@ -0,0 +1,13 @@ +// Identifier reference in nested computed question +form testForm { + "First Question" + firstCondition : boolean + "Second Question" + firstInteger : integer + if (firstCondition) { + "Third Question" + anotherIdentifier : integer + "Fourth Question" + yetAnotherIdentifier : integer = firstInteger + 1 + } +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test007.ql b/ql/test/semantic_analysis/valid/test007.ql new file mode 100644 index 0000000..1338a82 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test007.ql @@ -0,0 +1,9 @@ +// Identifier reference in both condition and computed question +form testForm { + "First Question" + someInteger : integer + if (someInteger > 10) { + "Second Question" + computedInteger : integer = someInteger - 10 + } +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test008.ql b/ql/test/semantic_analysis/valid/test008.ql new file mode 100644 index 0000000..80205a5 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test008.ql @@ -0,0 +1,9 @@ +// Identifier dependant on second, second dependant on third +form testForm { + "First Question" + firstIdentifier : integer = secondIdentifier + 1 + "Second Question" + secondIdentifier : integer = thirdIdentifier + 1 + "Third Question" + thirdIdentifier : integer +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test009.ql b/ql/test/semantic_analysis/valid/test009.ql new file mode 100644 index 0000000..7e92ad7 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test009.ql @@ -0,0 +1,7 @@ +// Different questions with equal labels +form testForm { + "First Question" + someIdentifier : integer + "First Question" + anotherIdentifier : decimal +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test010.ql b/ql/test/semantic_analysis/valid/test010.ql new file mode 100644 index 0000000..eca4ad4 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test010.ql @@ -0,0 +1,5 @@ +// Compatible types for addition operation +form testForm { + "First Question" + someIdentifier : decimal = 10.0 + 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test011.ql b/ql/test/semantic_analysis/valid/test011.ql new file mode 100644 index 0000000..f47b435 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test011.ql @@ -0,0 +1,5 @@ +// Compatible types for subtraction operation +form testForm { + "First Question" + someIdentifier : decimal = 10.0 - 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test012.ql b/ql/test/semantic_analysis/valid/test012.ql new file mode 100644 index 0000000..2e7e278 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test012.ql @@ -0,0 +1,5 @@ +// Compatible types for greater equals operation +form testForm { + "First Question" + someIdentifier : boolean = 10.0 == 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test013.ql b/ql/test/semantic_analysis/valid/test013.ql new file mode 100644 index 0000000..a34566c --- /dev/null +++ b/ql/test/semantic_analysis/valid/test013.ql @@ -0,0 +1,5 @@ +// Compatible types for greater than operation +form testForm { + "First Question" + someIdentifier : boolean = 10.0 > 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test014.ql b/ql/test/semantic_analysis/valid/test014.ql new file mode 100644 index 0000000..7ee1b86 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test014.ql @@ -0,0 +1,5 @@ +// Compatible types for less equals operation +form testForm { + "First Question" + someIdentifier : boolean = 10.0 <= 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test015.ql b/ql/test/semantic_analysis/valid/test015.ql new file mode 100644 index 0000000..431c1f0 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test015.ql @@ -0,0 +1,5 @@ +// Compatible types for less than operation +form testForm { + "First Question" + someIdentifier : boolean = 10.0 < 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test016.ql b/ql/test/semantic_analysis/valid/test016.ql new file mode 100644 index 0000000..8b0bdde --- /dev/null +++ b/ql/test/semantic_analysis/valid/test016.ql @@ -0,0 +1,5 @@ +// Compatible types for and operation +form testForm { + "First Question" + someIdentifier : boolean = True && False +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test017.ql b/ql/test/semantic_analysis/valid/test017.ql new file mode 100644 index 0000000..851e5ff --- /dev/null +++ b/ql/test/semantic_analysis/valid/test017.ql @@ -0,0 +1,5 @@ +// Compatible types for or operation +form testForm { + "First Question" + someIdentifier : boolean = False || True +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test018.ql b/ql/test/semantic_analysis/valid/test018.ql new file mode 100644 index 0000000..41d439f --- /dev/null +++ b/ql/test/semantic_analysis/valid/test018.ql @@ -0,0 +1,5 @@ +// Compatible types for multiplication operation +form testForm { + "First Question" + someIdentifier : decimal = 10.0 * 10 +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test019.ql b/ql/test/semantic_analysis/valid/test019.ql new file mode 100644 index 0000000..36ba458 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test019.ql @@ -0,0 +1,5 @@ +// Compatible types for division operation +form testForm { + "First Question" + someIdentifier : decimal = 10.0 / 10 +} diff --git a/ql/test/semantic_analysis/valid/test020.ql b/ql/test/semantic_analysis/valid/test020.ql new file mode 100644 index 0000000..9fff193 --- /dev/null +++ b/ql/test/semantic_analysis/valid/test020.ql @@ -0,0 +1,7 @@ +// Complex condition with mixed types +form testForm { + if ((15.5 >= 15) && ((3.0 * 3) - 15 > -10 / 2)) { + "First Question" + someIdentifier : integer + } +}
\ No newline at end of file diff --git a/ql/test/semantic_analysis/valid/test021.ql b/ql/test/semantic_analysis/valid/test021.ql new file mode 100644 index 0000000..01ec35c --- /dev/null +++ b/ql/test/semantic_analysis/valid/test021.ql @@ -0,0 +1,5 @@ +// Complex computed question with mixed types +form testForm { + "First Question" + someIdentifier : boolean = (25.5 >= 10) && ((10.0 / 3) - 15 < -10 * 2) +}
\ No newline at end of file diff --git a/ql/test/test.py b/ql/test/test.py new file mode 100644 index 0000000..79b67d4 --- /dev/null +++ b/ql/test/test.py @@ -0,0 +1,80 @@ +from os import listdir +from os import path + +from termcolor import colored + + +class Test: + def __init__(self, name, directory): + self.__name = name + self.directory = directory + self.valid_files = self.get_directory_files(directory + 'valid') + self.invalid_files = self.get_directory_files(directory + 'invalid') + + @property + def name(self): + return self.__name + + @staticmethod + def get_directory_files(directory): + if path.exists(directory): + return sorted(listdir(directory)) + + return [] + + def test(self): + successes = 0 + print('-------------------------------------------------------------------------------------------\n') + print('Performing {} tests.\n'.format(self.name)) + print('-------------------------------------------------------------------------------------------\n') + + if self.valid_files: + print('Performing valid tests:') + successes += self.test_valid_files() + print() + + if self.invalid_files: + print('Performing invalid tests:') + successes += self.test_invalid_files() + print() + + print('{} out of {} {} tests successful.\n'.format(successes, len(self.valid_files) + len(self.invalid_files), + self.name)) + + def test_file(self, file): + pass + + def test_valid_files(self, valid=True): + successes = 0 + + for file in self.valid_files: + test = open(self.directory + 'valid/' + file, 'r').read() + result = valid == self.test_file(test) + self.print_result(file, result, test.split('\n')[0]) + + if result: + successes += 1 + + return successes + + def test_invalid_files(self, valid=False): + successes = 0 + + for file in self.invalid_files: + test = open(self.directory + 'invalid/' + file, 'r').read() + result = valid == self.test_file(test) + self.print_result(file, result, test.split('\n')[0]) + + if result: + successes += 1 + + return successes + + @staticmethod + def print_result(file, result=True, test=''): + tag = colored('[failure]', 'red') + + if result: + tag = colored('[success]', 'green') + + print(tag, file, test.strip('//').strip()) diff --git a/ql/types/__pycache__/boolean.cpython-35.pyc b/ql/types/__pycache__/boolean.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..0acd5ee --- /dev/null +++ b/ql/types/__pycache__/boolean.cpython-35.pyc diff --git a/ql/types/__pycache__/date.cpython-35.pyc b/ql/types/__pycache__/date.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..389ffc4 --- /dev/null +++ b/ql/types/__pycache__/date.cpython-35.pyc diff --git a/ql/types/__pycache__/decimal.cpython-35.pyc b/ql/types/__pycache__/decimal.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..03e70c2 --- /dev/null +++ b/ql/types/__pycache__/decimal.cpython-35.pyc diff --git a/ql/types/__pycache__/integer.cpython-35.pyc b/ql/types/__pycache__/integer.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..eacf953 --- /dev/null +++ b/ql/types/__pycache__/integer.cpython-35.pyc diff --git a/ql/types/__pycache__/money.cpython-35.pyc b/ql/types/__pycache__/money.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..4213628 --- /dev/null +++ b/ql/types/__pycache__/money.cpython-35.pyc diff --git a/ql/types/__pycache__/string.cpython-35.pyc b/ql/types/__pycache__/string.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..18b2f54 --- /dev/null +++ b/ql/types/__pycache__/string.cpython-35.pyc diff --git a/ql/types/__pycache__/type.cpython-35.pyc b/ql/types/__pycache__/type.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..f81c2f7 --- /dev/null +++ b/ql/types/__pycache__/type.cpython-35.pyc diff --git a/ql/types/__pycache__/undefined.cpython-35.pyc b/ql/types/__pycache__/undefined.cpython-35.pyc Binary files differnew file mode 100644 index 0000000..ddc6cc1 --- /dev/null +++ b/ql/types/__pycache__/undefined.cpython-35.pyc diff --git a/ql/types/boolean.py b/ql/types/boolean.py new file mode 100644 index 0000000..f9dc76c --- /dev/null +++ b/ql/types/boolean.py @@ -0,0 +1,42 @@ +from gui.widgets.checkbox import CheckBox +from ql.ast.nodes.expressions.literals.boolean_literal import BooleanNode +from ql.types.type import QLType + + +class QLBoolean(QLType): + def __init__(self, value=False): + super(QLBoolean, self).__init__() + self.__value = bool(value) + + @property + def value(self): + return self.__value + + def __bool__(self): + return bool(self.value) + + def __str__(self): + return str(self.value) + + def __repr__(self): + return str(self.value) + + def __eq__(self, other): + if isinstance(other, QLBoolean): + return QLBoolean(self.value == other.value) + + return QLBoolean(False) + + def __ne__(self, other): + return QLBoolean(not self == other) + + def get_json_value(self): + return self.value + + @staticmethod + def get_literal_node(value): + return BooleanNode(None, QLBoolean, value) + + @staticmethod + def pyqt5_default_widget(): + return CheckBox() diff --git a/ql/types/date.py b/ql/types/date.py new file mode 100644 index 0000000..fca5366 --- /dev/null +++ b/ql/types/date.py @@ -0,0 +1,67 @@ +from datetime import date + +from gui.widgets.calendar import CalendarWidget +from ql.ast.nodes.expressions.literals.date_literal import DateNode +from ql.types.boolean import QLBoolean +from ql.types.type import QLType + + +class QLDate(QLType): + def __init__(self, day=1, month=1, year=1): + super(QLDate, self).__init__() + self.__day = int(day) + self.__month = int(month) + self.__year = int(year) + date(self.year, self.month, self.day) + + @property + def day(self): + return self.__day + + @property + def month(self): + return self.__month + + @property + def year(self): + return self.__year + + def __repr__(self): + return '{}-{}-{}'.format(self.day, self.month, self.year) + + def __str__(self): + return '{}-{}-{}'.format(self.day, self.month, self.year) + + def __eq__(self, other): + if isinstance(other, QLDate): + return QLBoolean(self.day == other.day and self.month == other.month and self.year == other.year) + + return QLBoolean(False) + + def __ne__(self, other): + return QLBoolean(not self == other) + + def __lt__(self, other): + return QLBoolean(self.year < other.year or (self.month < other.month and self.year == other.year) or + (self.day < other.day and self.month == other.month and self.year == other.year)) + + def __gt__(self, other): + return QLBoolean(self.year > other.year or (self.month > other.month and self.year == other.year) or + (self.day > other.day and self.month == other.month and self.year == other.year)) + + def __le__(self, other): + return QLBoolean(self < other or self == other) + + def __ge__(self, other): + return QLBoolean(self > other or self == other) + + def get_json_value(self): + return {'day': self.day, 'month': self.month, 'year': self.year} + + @staticmethod + def get_literal_node(value): + return DateNode(None, QLDate, value) + + @staticmethod + def pyqt5_default_widget(): + return CalendarWidget() diff --git a/ql/types/decimal.py b/ql/types/decimal.py new file mode 100644 index 0000000..af0952d --- /dev/null +++ b/ql/types/decimal.py @@ -0,0 +1,74 @@ +from gui.widgets.double_spinbox import DoubleSpinBox +from ql.ast.nodes.expressions.literals.decimal_literal import DecimalNode +from ql.types.boolean import QLBoolean +from ql.types.money import QLMoney +from ql.types.type import QLType + + +class QLDecimal(QLType): + def __init__(self, value=0.0): + super(QLDecimal, self).__init__() + self.__value = float(value) + + @property + def value(self): + return self.__value + + def __repr__(self): + return str(self.value) + + def __str__(self): + return str(self.value) + + def __neg__(self): + return QLDecimal(- self.value) + + def __eq__(self, other): + if isinstance(other, QLDecimal): + return QLBoolean(self.value == other.value) + + return QLBoolean(False) + + def __ne__(self, other): + return QLBoolean(not self == other) + + def __lt__(self, other): + return QLBoolean(self.value < other.value) + + def __gt__(self, other): + return QLBoolean(self.value > other.value) + + def __le__(self, other): + return QLBoolean(self.value <= other.value) + + def __ge__(self, other): + return QLBoolean(self.value >= other.value) + + def __add__(self, other): + return QLDecimal(self.value + other.value) + + def __sub__(self, other): + return QLDecimal(self.value - other.value) + + def __mul__(self, other): + if isinstance(other, QLMoney): + return QLMoney(self.value * other.value, other.currency) + + return QLDecimal(self.value * other.value) + + def __truediv__(self, other): + if isinstance(other, QLMoney): + return QLMoney(other.value / self.value, other.currency) + + return QLDecimal(self.value / other.value) + + def get_json_value(self): + return self.value + + @staticmethod + def get_literal_node(value): + return DecimalNode(None, QLDecimal, value) + + @staticmethod + def pyqt5_default_widget(): + return DoubleSpinBox() diff --git a/ql/types/integer.py b/ql/types/integer.py new file mode 100644 index 0000000..ddc8666 --- /dev/null +++ b/ql/types/integer.py @@ -0,0 +1,75 @@ +from gui.widgets.spinbox import SpinBox +from ql.ast.nodes.expressions.literals.integer_literal import IntegerNode +from ql.types.boolean import QLBoolean +from ql.types.decimal import QLDecimal +from ql.types.money import QLMoney +from ql.types.type import QLType + + +class QLInteger(QLType): + def __init__(self, value=0): + super(QLInteger, self).__init__() + self.__value = int(value) + + @property + def value(self): + return self.__value + + def __repr__(self): + return str(self.value) + + def __str__(self): + return str(self.value) + + def __neg__(self): + return QLInteger(- self.value) + + def __eq__(self, other): + if isinstance(other, QLInteger): + return QLBoolean(self.value == other.value) + + return QLBoolean(False) + + def __ne__(self, other): + return QLBoolean(not self == other) + + def __lt__(self, other): + return QLBoolean(self.value < other.value) + + def __gt__(self, other): + return QLBoolean(self.value > other.value) + + def __le__(self, other): + return QLBoolean(self.value <= other.value) + + def __ge__(self, other): + return QLBoolean(self.value >= other.value) + + def __add__(self, other): + return type(other)(self.value + other.value) + + def __sub__(self, other): + return type(other)(self.value - other.value) + + def __mul__(self, other): + if isinstance(other, QLMoney): + return QLMoney(self.value * other.value, other.currency) + + return type(other)(self.value * other.value) + + def __truediv__(self, other): + if isinstance(other, QLMoney): + return QLMoney(other.value / self.value, other.currency) + + return QLDecimal(self.value / other.value) + + def get_json_value(self): + return self.value + + @staticmethod + def get_literal_node(value): + return IntegerNode(None, QLInteger, value) + + @staticmethod + def pyqt5_default_widget(): + return SpinBox() diff --git a/ql/types/money.py b/ql/types/money.py new file mode 100644 index 0000000..edac58f --- /dev/null +++ b/ql/types/money.py @@ -0,0 +1,76 @@ +from gui.widgets.money_spinbox import MoneySpinbox +from ql.ast.nodes.expressions.literals.money_literal import MoneyNode +from ql.types.boolean import QLBoolean +from ql.types.type import QLType + + +class QLMoney(QLType): + def __init__(self, value=0.0, currency='$'): + super(QLMoney, self).__init__() + self.__value = float(value) + self.__currency = currency + + @property + def value(self): + return self.__value + + @property + def currency(self): + return self.__currency + + def __repr__(self): + return '{}{:.2f}'.format(self.currency, self.value) + + def __str__(self): + return '{}{:.2f}'.format(self.currency, self.value) + + def __neg__(self): + return QLMoney(- self.value, self.currency) + + def __eq__(self, other): + if isinstance(other, QLMoney): + return QLBoolean(self.value == other.value and self.currency == other.currency) + + return QLBoolean(False) + + def __ne__(self, other): + return QLBoolean(not self == other) + + def __lt__(self, other): + return QLBoolean(self.value < other.value and self.currency == other.currency) + + def __gt__(self, other): + return QLBoolean(self.value > other.value and self.currency == other.currency) + + def __le__(self, other): + return QLBoolean(self.value <= other.value and self.currency == other.currency) + + def __ge__(self, other): + return QLBoolean(self.value >= other.value and self.currency == other.currency) + + def __add__(self, other): + if self.currency == other.currency: + return QLMoney(self.value + other.value, self.currency) + return NotImplemented + + def __sub__(self, other): + if self.currency == other.currency: + return QLMoney(self.value - other.value, self.currency) + return NotImplemented + + def __mul__(self, other): + return other * self + + def __truediv__(self, other): + return other / self + + def get_json_value(self): + return {'value': round(self.value, 2), 'currency': self.currency} + + @staticmethod + def get_literal_node(value): + return MoneyNode(None, QLMoney, value) + + @staticmethod + def pyqt5_default_widget(): + return MoneySpinbox() diff --git a/ql/types/string.py b/ql/types/string.py new file mode 100644 index 0000000..ece46a7 --- /dev/null +++ b/ql/types/string.py @@ -0,0 +1,55 @@ +from gui.widgets.line_edit import LineEdit +from ql.ast.nodes.expressions.literals.string_literal import StringNode +from ql.types.boolean import QLBoolean +from ql.types.type import QLType + + +class QLString(QLType): + def __init__(self, value=''): + super(QLString, self).__init__() + self.__value = str(value) + + @property + def value(self): + return self.__value + + def __repr__(self): + return str(self.value) + + def __str__(self): + return str(self.value) + + def __eq__(self, other): + if isinstance(other, QLString): + return QLBoolean(self.value == other.value) + + return QLBoolean(False) + + def __ne__(self, other): + return QLBoolean(not self == other) + + def __lt__(self, other): + return QLBoolean(len(self.value) < len(other.value)) + + def __gt__(self, other): + return QLBoolean(len(self.value) > len(other.value)) + + def __le__(self, other): + return QLBoolean(len(self.value) <= len(other.value)) + + def __ge__(self, other): + return QLBoolean(len(self.value) >= len(other.value)) + + def __add__(self, other): + return QLString(self.value + other.value) + + def get_json_value(self): + return self.value + + @staticmethod + def get_literal_node(value): + return StringNode(None, QLString, value) + + @staticmethod + def pyqt5_default_widget(): + return LineEdit() diff --git a/ql/types/type.py b/ql/types/type.py new file mode 100644 index 0000000..912946d --- /dev/null +++ b/ql/types/type.py @@ -0,0 +1,3 @@ +class QLType: + def __init__(self): + pass diff --git a/ql/types/undefined.py b/ql/types/undefined.py new file mode 100644 index 0000000..2deafe0 --- /dev/null +++ b/ql/types/undefined.py @@ -0,0 +1,40 @@ +from gui.widgets.label import Label +from ql.ast.nodes.expressions.literals.undefined_literal import UndefinedNode +from ql.types.boolean import QLBoolean +from ql.types.type import QLType + + +class QLUndefined(QLType): + def __init__(self, *unused): + super(QLUndefined, self).__init__() + self.__value = None + + @property + def value(self): + return self.__value + + def __bool__(self): + return False + + def __repr__(self): + return 'Undefined' + + def __eq__(self, other): + if isinstance(other, QLUndefined): + return QLBoolean(self.value == other.value) + + return QLBoolean(False) + + def __ne__(self, other): + return QLBoolean(not self == other) + + def get_json_value(self): + return self.value + + @staticmethod + def get_literal_node(unused): + return UndefinedNode(None, QLUndefined, QLUndefined(None)) + + @staticmethod + def pyqt5_default_widget(): + return Label('Undefined') diff --git a/qls/parser/lexer.py b/qls/parser/lexer.py new file mode 100644 index 0000000..f7b8b98 --- /dev/null +++ b/qls/parser/lexer.py @@ -0,0 +1,117 @@ +from ply.lex import lex
+
+
+class QLSLexer:
+ def __init__(self):
+ self.__errors = []
+ self.__lexer = None
+
+ @property
+ def lexer(self):
+ return self.__lexer
+
+ @property
+ def errors(self):
+ return self.__errors
+
+ def build(self):
+ self.__lexer = lex(module=self)
+
+ def tokenize(self, data):
+ self.__errors = []
+ self.lexer.input(data)
+ token = self.lexer.token()
+ tokens = [token]
+
+ while token:
+ token = self.lexer.token()
+ tokens.append(token)
+
+ return tokens
+
+ tokens = [
+ 'COLON', 'COMMA',
+ 'LEFT_BRACE', 'RIGHT_BRACE',
+ 'LEFT_BRACKET', 'RIGHT_BRACKET',
+ 'IDENTIFIER',
+ 'HEX_COLOR',
+ 'INTEGER_LITERAL', 'STRING_LITERAL',
+ ]
+
+ # List of reserved keywords
+ reserved = {
+ 'stylesheet': 'STYLESHEET',
+ 'page': 'PAGE',
+ 'section': 'SECTION',
+ 'question': 'QUESTION',
+ 'default': 'DEFAULT',
+
+ # Properties
+ 'height': 'HEIGHT',
+ 'width': 'WIDTH',
+ 'font': 'FONT',
+ 'fontsize': 'FONT_SIZE',
+ 'color': 'COLOR',
+ 'widget': 'WIDGET',
+
+ # QL types
+ 'boolean': 'BOOLEAN',
+ 'date': 'DATE',
+ 'decimal': 'DECIMAL',
+ 'integer': 'INTEGER',
+ 'money': 'MONEY',
+ 'string': 'STRING',
+
+ # Widgets
+ 'calendar': 'CALENDAR',
+ 'checkbox': 'CHECKBOX',
+ 'line_edit': 'LINE_EDIT',
+ 'spinbox': 'SPINBOX',
+ 'radio': 'RADIO',
+ }
+
+ tokens += list(reserved.values())
+
+ # Regular expression rules for simple tokens
+ t_ignore = ' \t'
+
+ t_COLON = r':'
+ t_COMMA = r','
+
+ t_LEFT_BRACE = r'\{'
+ t_RIGHT_BRACE = r'\}'
+
+ t_LEFT_BRACKET = r'\('
+ t_RIGHT_BRACKET = r'\)'
+
+ t_HEX_COLOR = r'\#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})'
+
+ @staticmethod
+ def t_newline(token):
+ r'\n+'
+ token.lexer.lineno += len(token.value)
+
+ @staticmethod
+ def t_eof(token):
+ token.lexer.lineno = 1
+
+ @staticmethod
+ def t_INTEGER_LITERAL(token):
+ r'\d+'
+ token.value = int(token.value)
+ return token
+
+ @staticmethod
+ def t_STRING_LITERAL(token):
+ r'\"(.+?)\"'
+ token.value = token.value[1:-1]
+ return token
+
+ def t_IDENTIFIER(self, token):
+ r'[a-zA-Z][a-zA-Z_0-9]*'
+ token.type = self.reserved.get(token.value, 'IDENTIFIER') # Check for reserved words
+ return token
+
+ def t_error(self, token):
+ self.errors.append("Illegal character '%s'" % token.value[0])
+ token.lexer.skip(1)
diff --git a/qls/parser/parser.py b/qls/parser/parser.py new file mode 100644 index 0000000..1637e6d --- /dev/null +++ b/qls/parser/parser.py @@ -0,0 +1,215 @@ +from ply.yacc import yacc + +from qls.parser.lexer import QLSLexer + + +class QLSParser: + def __init__(self): + self.__errors = [] + self.__tokens = QLSLexer.tokens + self.__parser = None + + @property + def errors(self): + return self.__errors + + @property + def tokens(self): + return self.__tokens + + @property + def parser(self): + return self.__parser + + def build(self): + self.__parser = yacc(module=self) + + def parse(self, data, lexer): + return self.parser.parse(data, lexer) + + @staticmethod + def p_stylesheet(production): + """stylesheet : STYLESHEET IDENTIFIER LEFT_BRACE pages RIGHT_BRACE""" + production[0] = ('STYLESHEET', production[2], production[4]) + + # Statements + @staticmethod + def p_pages(production): + """pages : page pages + | page""" + if len(production) == 3: + production[0] = [production[1]] + production[2] + elif len(production) == 2: + production[0] = [production[1]] + + @staticmethod + def p_page(production): + """page : PAGE IDENTIFIER LEFT_BRACE sections RIGHT_BRACE + | PAGE IDENTIFIER LEFT_BRACE sections default RIGHT_BRACE + | PAGE IDENTIFIER LEFT_BRACE default RIGHT_BRACE""" + if len(production) == 6: + production[0] = ('PAGE', production[2], production[4]) + elif len(production) == 7: + production[0] = ('PAGE', production[2], production[4], production[5]) + + @staticmethod + def p_sections(production): + """sections : section sections + | section""" + if len(production) == 3: + production[0] = [production[1]] + production[2] + elif len(production) == 2: + production[0] = [production[1]] + + @staticmethod + def p_statement(production): + """statement : section + | question""" + production[0] = production[1] + + @staticmethod + def p_statements(production): + """statements : statement statements + | statement""" + if len(production) == 3: + production[0] = [production[1]] + production[2] + elif len(production) == 2: + production[0] = [production[1]] + + @staticmethod + def p_section(production): + """section : SECTION STRING_LITERAL LEFT_BRACE statements RIGHT_BRACE + | SECTION STRING_LITERAL LEFT_BRACE statements default RIGHT_BRACE + | SECTION STRING_LITERAL question + | SECTION STRING_LITERAL default""" + if len(production) == 4: + production[0] = ('SECTION', production[2], [production[3]]) + elif len(production) == 6: + production[0] = ('SECTION', production[2], production[4]) + elif len(production) == 7: + production[0] = ('SECTION', production[2], production[4], production[5]) + + @staticmethod + def p_question(production): + """question : QUESTION IDENTIFIER""" + production[0] = ('QUESTION', production[2]) + + @staticmethod + def p_question_properties(production): + """question : QUESTION IDENTIFIER WIDGET widget""" + production[0] = ('QUESTION', production[2], production[4]) + + @staticmethod + def p_default(production): + """default : DEFAULT type LEFT_BRACE properties RIGHT_BRACE""" + production[0] = ('DEFAULT', production[2], production[4]) + + @staticmethod + def p_default_widget(production): + """default : DEFAULT type WIDGET widget""" + production[0] = ('DEFAULT', production[2], production[3]) + + # Properties + @staticmethod + def p_properties(production): + """properties : property properties + | property""" + if len(production) == 3: + production[0] = [production[1]] + production[2] + elif len(production) == 2: + production[0] = [production[1]] + + @staticmethod + def p_height(production): + """property : HEIGHT COLON INTEGER_LITERAL""" + production[0] = ('HEIGHT', production[3]) + + @staticmethod + def p_width(production): + """property : WIDTH COLON INTEGER_LITERAL""" + production[0] = ('WIDTH', production[3]) + + @staticmethod + def p_font(production): + """property : FONT COLON STRING_LITERAL""" + production[0] = ('FONT', production[3]) + + @staticmethod + def p_font_size(production): + """property : FONT_SIZE COLON INTEGER_LITERAL""" + production[0] = ('FONT_SIZE', production[3]) + + @staticmethod + def p_color(production): + """property : COLOR COLON HEX_COLOR""" + production[0] = ('COLOR', production[3]) + + @staticmethod + def p_widget(production): + """property : WIDGET widget""" + production[0] = ('WIDGET', production[2]) + + # Widgets + @staticmethod + def p_calendar(production): + """widget : CALENDAR""" + production[0] = 'CALENDAR' + + @staticmethod + def p_checkbox(production): + """widget : CHECKBOX""" + production[0] = 'CHECKBOX' + + @staticmethod + def p_line_edit(production): + """widget : LINE_EDIT""" + production[0] = 'LINE_EDIT' + + @staticmethod + def p_spinbox(production): + """widget : SPINBOX""" + production[0] = 'SPINBOX' + + @staticmethod + def p_radio_default(production): + """widget : RADIO""" + production[0] = 'RADIO' + + @staticmethod + def p_radio(production): + """widget : RADIO LEFT_BRACKET STRING_LITERAL COMMA STRING_LITERAL RIGHT_BRACKET""" + production[0] = ('RADIO', production[3], production[5]) + + # Types + @staticmethod + def p_boolean(production): + """type : BOOLEAN""" + production[0] = 'BOOLEAN' + + @staticmethod + def p_decimal(production): + """type : DECIMAL""" + production[0] = 'DECIMAL' + + @staticmethod + def p_string(production): + """type : STRING""" + production[0] = 'STRING' + + @staticmethod + def p_date(production): + """type : DATE""" + production[0] = 'DATE' + + @staticmethod + def p_money(production): + """type : MONEY""" + production[0] = 'MONEY' + + @staticmethod + def p_integer(production): + """type : INTEGER""" + production[0] = 'INTEGER' + + def p_error(self, production): + self.errors.append('Syntax error at line {}, token={}'.format(production.lineno, production.type)) |