Skip to content

Commit

Permalink
general error improvements & extensive syntax error checking for vectors
Browse files Browse the repository at this point in the history
  • Loading branch information
bansheerubber committed Sep 1, 2020
1 parent d096453 commit b7ef43d
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 6 deletions.
77 changes: 76 additions & 1 deletion expressions/vector_expression.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from enum import IntEnum
from expression import Expression
from literal import Literal
from method_expression import MethodExpression
Expand All @@ -8,6 +9,7 @@
from syntax_exception import SyntaxException
from vector_escape_expression import VectorEscapeExpression
from vector_length_expression import VectorLengthExpression
from warn import warn

class VectorExpression(Expression):
def __init__(self, tokenizer=None):
Expand Down Expand Up @@ -93,6 +95,19 @@ def handle_parentheses_expressions(self, expression=None):
self.handle_order_of_operations(expression=found_expression)

def handle_order_of_operations(self, offset=0, min_precedence=0, expression=None):
def is_maybe_scalar_expression(expression):
# checking to see if this expression is a scalar expression
if (
type(expression) == VectorEscapeExpression
or (
type(expression) == MethodExpression
and expression.method_symbol.name == "vectorDot"
)
):
return True
else:
return False

if expression == None:
expression = self

Expand Down Expand Up @@ -126,6 +141,43 @@ def handle_order_of_operations(self, offset=0, min_precedence=0, expression=None
raise SyntaxException(self, f"Vector expression syntax error: invalid operator {operator.operator}")
elif next_operator != None and next_operator.operator not in VectorExpression.operator_table:
raise SyntaxException(self, f"Vector expression syntax error: invalid operator {next_operator.operator}")

# check for type errors
if (
VectorExpression.operator_allows_scalars[operator.operator] == OperatorScalarOption.NO_SCALARS
):
if (
(
is_maybe_scalar_expression(left_vector) == True
and is_maybe_scalar_expression(right_vector) == False
)
or (
is_maybe_scalar_expression(left_vector) == False
and is_maybe_scalar_expression(right_vector) == True
)
):
raise SyntaxException(self, f"Vector expression syntax error: cannot mix scalars and vectors for operator {operator.operator} at {left_vector.to_script()} {operator.operator} {right_vector.to_script()}")
elif (
is_maybe_scalar_expression(left_vector) == True
and is_maybe_scalar_expression(right_vector) == True
):
raise SyntaxException(self, f"Vector expression syntax error: only vector operations are allowed inside backticks, not {left_vector.to_script()} {operator.operator} {right_vector.to_script()}. To escape, use the vector escape syntax " + "{}")
elif (
VectorExpression.operator_allows_scalars[operator.operator] == OperatorScalarOption.RIGHT_OR_LEFT_SCALAR
or VectorExpression.operator_allows_scalars[operator.operator] == OperatorScalarOption.ONLY_RIGHT_SCALAR
):
if VectorExpression.operator_allows_scalars[operator.operator] == OperatorScalarOption.ONLY_RIGHT_SCALAR and is_maybe_scalar_expression(left_vector) == True:
raise SyntaxException(self, f"Vector expression syntax error: the {operator.operator} operator does not support left-handed scalar operations at {left_vector.to_script()} {operator.operator} {right_vector.to_script()}")
elif (
is_maybe_scalar_expression(left_vector) == False
and is_maybe_scalar_expression(right_vector) == False
):
warn(self, f"Vector expression syntax warning: implicit usage of scalars for operator {operator.operator} at {left_vector.to_script()} {operator.operator} {right_vector.to_script()}. Will only work at run-time if right-hand side is a scalar")
elif (
is_maybe_scalar_expression(left_vector) == True
and is_maybe_scalar_expression(right_vector) == True
):
raise SyntaxException(self, f"Vector expression syntax error: only vector operations are allowed inside backticks, not {left_vector.to_script()} {operator.operator} {right_vector.to_script()}. To escape, use the vector escape syntax " + "{}")

# do precedence rules
if next_operator != None:
Expand All @@ -135,6 +187,15 @@ def handle_order_of_operations(self, offset=0, min_precedence=0, expression=None
# these operands may have changed due to precedence rules. re-fetch
left_vector = expression.safe_get_index(0 + offset)
right_vector = expression.safe_get_index(2 + offset)

# determine which vector is a scalar and if we need to flip the sides
if (
VectorExpression.operator_allows_scalars[operator.operator] == 1
and is_maybe_scalar_expression(left_vector)
):
right_vector = expression.safe_get_index(0 + offset)
left_vector = expression.safe_get_index(2 + offset)

self.replace_operation_with_call(offset, left_vector, operator, right_vector, expression=expression)
self.handle_order_of_operations(offset=offset, expression=expression)

Expand Down Expand Up @@ -190,7 +251,21 @@ def replace_operation_with_call(self, index_of_left, left_vector, operator, righ
method_expression.expressions.append(argument)
method_expression.convert_expressions_to_arguments()
method_expression.convert_expressions_to_arguments()


class OperatorScalarOption(IntEnum):
NO_SCALARS = 0
RIGHT_OR_LEFT_SCALAR = 1
ONLY_RIGHT_SCALAR = 2


VectorExpression.operator_allows_scalars = {
"+": OperatorScalarOption.NO_SCALARS,
"*": OperatorScalarOption.RIGHT_OR_LEFT_SCALAR,
"-": OperatorScalarOption.NO_SCALARS,
"/": OperatorScalarOption.ONLY_RIGHT_SCALAR,
".": OperatorScalarOption.NO_SCALARS,
}

VectorExpression.operator_table = {
"+": (Symbol("vectorAdd"), [None], [None]),
"*": (Symbol("vectorScale"), [None], [None]),
Expand Down
3 changes: 1 addition & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,5 @@ def create_watcher(path):
arguments = " ".join(sys.argv[1:])
if "-v" in arguments or "--verbose" in arguments:
traceback.print_exc()
print(f"Encountered exception '{error.__str__()}'")
else:
print_help()
print(f"\033[91mEncountered exception '{error.__str__()}'\033[0m")
2 changes: 1 addition & 1 deletion syntax_exception.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
class SyntaxException(Exception):
def __init__(self, expression, message):
super().__init__(f"{message} at line #{expression.current_line_index} character #{expression.current_index} file '{expression.current_file_name}''")
super().__init__(f"{message} at line #{expression.current_line_index} character #{expression.current_index} file '{expression.current_file_name}'")
6 changes: 4 additions & 2 deletions tokenizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,10 @@ def tokenize(self, stop_ats=[], give_back_stop_ats=[], buffer_give_back_stop_at=
else: # when in doubt, add to buffer
self.buffer = self.buffer + char
except Exception as error:
traceback.print_exc()
print(f"Encountered exception '{error.__str__()}' at line #{self.file.current_line_index} character #{self.file.current_index}")
if get_config("verbose") == True:
traceback.print_exc()

print(f"\033[91mEncountered exception '{error.__str__()}' at line #{self.file.current_line_index} character #{self.file.current_index}\033[0m")
return None

return tree
2 changes: 2 additions & 0 deletions warn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def warn(expression, message):
print(f"\033[93m{message} at line #{expression.current_line_index} character #{expression.current_index} file '{expression.current_file_name}'\033[0m")

0 comments on commit b7ef43d

Please sign in to comment.