Skip to content

Commit

Permalink
Add new indent errors for level introducing indent #3270
Browse files Browse the repository at this point in the history
  • Loading branch information
boryanagoncharenko committed Mar 20, 2024
1 parent 9ac22c4 commit c4db1f6
Show file tree
Hide file tree
Showing 57 changed files with 853 additions and 466 deletions.
4 changes: 2 additions & 2 deletions content/error-messages.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ gettext('Invalid Argument Type')
gettext('Invalid Argument')
gettext('Invalid Type Combination')
gettext('Unsupported Float')
gettext('Locked Language Feature')
gettext('Too Many Indents')
gettext('Too Few Indents')
gettext('Missing Command')
gettext('Missing Inner Command')
gettext('Missing Variable')
Expand All @@ -46,7 +47,6 @@ gettext('single quotes')
gettext('double quotes')
gettext('slash')
gettext('string')
gettext('nested blocks')
gettext('or')
gettext('number')
gettext('integer')
Expand Down
17 changes: 12 additions & 5 deletions exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,18 @@ def __init__(self, line_number):
super().__init__('Has Blanks', line_number=line_number)


class TooManyIndentsStartLevelException(HedyException):
def __init__(self, line_number, leading_spaces, fixed_code=None):
super().__init__('Too Many Indents', line_number=line_number, leading_spaces=leading_spaces)
self.fixed_code = fixed_code


class TooFewIndentsStartLevelException(HedyException):
def __init__(self, line_number, leading_spaces, fixed_code=None):
super().__init__('Too Few Indents', line_number=line_number, leading_spaces=leading_spaces)
self.fixed_code = fixed_code


class NoIndentationException(HedyException):
def __init__(self, line_number, leading_spaces, indent_size, fixed_code=None):
super().__init__('No Indentation',
Expand All @@ -324,11 +336,6 @@ def __init__(self, value):
super().__init__('Unsupported Float', value=value)


class LockedLanguageFeatureException(HedyException):
def __init__(self, concept):
super().__init__('Locked Language Feature', concept=concept)


class UnsupportedStringValue(HedyException):
def __init__(self, invalid_value):
super().__init__('Unsupported String Value', invalid_value=invalid_value)
Expand Down
44 changes: 28 additions & 16 deletions hedy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3339,39 +3339,33 @@ def preprocess_blocks(code, level, lang):
indent_size = leading_spaces
indent_size_adapted = True

# indentation size not 4
# there is inconsistent indentation, not sure if that is too much or too little!
if (leading_spaces % indent_size) != 0:
# there is inconsistent indentation, not sure if that is too much or too little!
fixed_code = program_repair.fix_indent(code, line_number, leading_spaces, indent_size)
if leading_spaces < current_number_of_indents * indent_size:
fixed_code = program_repair.fix_indent(code, line_number, leading_spaces, indent_size)
raise hedy.exceptions.NoIndentationException(line_number=line_number, leading_spaces=leading_spaces,
indent_size=indent_size, fixed_code=fixed_code)
raise_too_few_indents_error(line_number, leading_spaces, indent_size, fixed_code, level)
else:
fixed_code = program_repair.fix_indent(code, line_number, leading_spaces, indent_size)
raise hedy.exceptions.IndentationException(line_number=line_number, leading_spaces=leading_spaces,
indent_size=indent_size, fixed_code=fixed_code)
raise_too_many_indents_error(line_number, leading_spaces, indent_size, fixed_code, level)

# happy path, multiple of 4 spaces:
# happy path, indentation is consistent, i.e. multiple of 2 or 4:
current_number_of_indents = leading_spaces // indent_size
if current_number_of_indents > 1 and level == hedy.LEVEL_STARTING_INDENTATION:
raise hedy.exceptions.LockedLanguageFeatureException(concept="nested blocks")
raise hedy.exceptions.TooManyIndentsStartLevelException(line_number=line_number,
leading_spaces=leading_spaces)

if current_number_of_indents > previous_number_of_indents and not next_line_needs_indentation:
# we are indenting, but this line is not following* one that even needs indenting, raise
# * note that we have not yet updated the value of 'next line needs indenting' so if refers to this line!
fixed_code = program_repair.fix_indent(code, line_number, leading_spaces, indent_size)
raise hedy.exceptions.IndentationException(line_number=line_number, leading_spaces=leading_spaces,
indent_size=indent_size, fixed_code=fixed_code)
raise_too_many_indents_error(line_number, leading_spaces, indent_size, fixed_code, level)

if next_line_needs_indentation and current_number_of_indents <= previous_number_of_indents:
fixed_code = program_repair.fix_indent(code, line_number, leading_spaces, indent_size)
raise hedy.exceptions.NoIndentationException(line_number=line_number, leading_spaces=leading_spaces,
indent_size=indent_size, fixed_code=fixed_code)
raise_too_few_indents_error(line_number, leading_spaces, indent_size, fixed_code, level)

if current_number_of_indents - previous_number_of_indents > 1:
fixed_code = program_repair.fix_indent(code, line_number, leading_spaces, indent_size)
raise hedy.exceptions.IndentationException(line_number=line_number, leading_spaces=leading_spaces,
indent_size=indent_size, fixed_code=fixed_code)
raise_too_many_indents_error(line_number, leading_spaces, indent_size, fixed_code, level)

if current_number_of_indents < previous_number_of_indents:
# we are dedenting ('jumping back) so we need to and an end-block
Expand Down Expand Up @@ -3399,6 +3393,24 @@ def preprocess_blocks(code, level, lang):
return "\n".join(processed_code)


def raise_too_many_indents_error(line_number, leading_spaces, indent_size, fixed_code, level):
if level == hedy.LEVEL_STARTING_INDENTATION:
raise hedy.exceptions.TooManyIndentsStartLevelException(line_number=line_number, leading_spaces=leading_spaces,
fixed_code=fixed_code)
else:
raise hedy.exceptions.IndentationException(line_number=line_number, leading_spaces=leading_spaces,
indent_size=indent_size, fixed_code=fixed_code)


def raise_too_few_indents_error(line_number, leading_spaces, indent_size, fixed_code, level):
if level == hedy.LEVEL_STARTING_INDENTATION:
raise hedy.exceptions.TooFewIndentsStartLevelException(line_number=line_number, leading_spaces=leading_spaces,
fixed_code=fixed_code)
else:
raise hedy.exceptions.NoIndentationException(line_number=line_number, leading_spaces=leading_spaces,
indent_size=indent_size, fixed_code=fixed_code)


def preprocess_ifs(code, lang='en'):
processed_code = []
lines = code.split("\n")
Expand Down
18 changes: 9 additions & 9 deletions messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2000-01-01 00:00+0000\n"
"PO-Revision-Date: 2000-01-01 00:00+0000\n"
"Last-Translator: Someone <[email protected]>\n"
"POT-Creation-Date: 2024-03-20 15:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
Expand Down Expand Up @@ -53,9 +53,6 @@ msgstr ""
msgid "Invalid Type Combination"
msgstr ""

msgid "Locked Language Feature"
msgstr ""

msgid "Lonely Echo"
msgstr ""

Expand Down Expand Up @@ -98,6 +95,12 @@ msgstr ""
msgid "Too Big"
msgstr ""

msgid "Too Few Indents"
msgstr ""

msgid "Too Many Indents"
msgstr ""

msgid "Unexpected Indentation"
msgstr ""

Expand Down Expand Up @@ -1010,9 +1013,6 @@ msgstr ""
msgid "nav_start"
msgstr ""

msgid "nested blocks"
msgstr ""

msgid "new_password"
msgstr ""

Expand Down
8 changes: 5 additions & 3 deletions tests/Tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,11 @@ def single_level_tester(
# because in that case our preprocessor throws the error so there is no parsetree
# (todo maybe parse first?)

skipped_exceptions = [hedy.exceptions.ParseException, hedy.exceptions.NoIndentationException,
hedy.exceptions.IndentationException, hedy.exceptions.LockedLanguageFeatureException,
hedy.exceptions.CodePlaceholdersPresentException]
skipped_exceptions = [
hedy.exceptions.ParseException, hedy.exceptions.CodePlaceholdersPresentException,
hedy.exceptions.TooFewIndentsStartLevelException, hedy.exceptions.TooManyIndentsStartLevelException,
hedy.exceptions.NoIndentationException, hedy.exceptions.IndentationException
]

if translate and exception not in skipped_exceptions and skipped_mappings is None:
self.verify_translation(code, lang, level)
Expand Down
32 changes: 14 additions & 18 deletions tests/test_level/test_level_08.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def test_if_no_indentation(self):

# gives the right exception for all levels even though it misses brackets
# because the indent check happens before parsing
self.multi_level_tester(code=code, exception=hedy.exceptions.NoIndentationException)
self.single_level_tester(code=code, exception=hedy.exceptions.TooFewIndentsStartLevelException)

def test_if_equality_with_is(self):
code = textwrap.dedent("""\
Expand Down Expand Up @@ -401,10 +401,8 @@ def test_if_else_no_indentation(self):
else
print 'bah slecht'""")

# gives the right exception for all levels even though it misses brackets
# because the indent check happens before parsing
self.multi_level_tester(code=code,
exception=hedy.exceptions.NoIndentationException)
self.single_level_tester(code=code,
exception=hedy.exceptions.TooFewIndentsStartLevelException)

def test_if_equality_print_else_print(self):
code = textwrap.dedent("""\
Expand Down Expand Up @@ -569,7 +567,7 @@ def test_repeat_no_indentation(self):
repeat 3 times
print 'hooray!'""")

self.multi_level_tester(code=code, exception=hedy.exceptions.NoIndentationException)
self.single_level_tester(code=code, exception=hedy.exceptions.TooFewIndentsStartLevelException)

def test_repeat_repair_too_few_indents(self):
code = textwrap.dedent("""\
Expand All @@ -582,9 +580,9 @@ def test_repeat_repair_too_few_indents(self):
print('repair')
print('me')""")

self.multi_level_tester(
self.single_level_tester(
code=code,
exception=hedy.exceptions.NoIndentationException,
exception=hedy.exceptions.TooFewIndentsStartLevelException,
extra_check_function=(lambda x: x.exception.fixed_code == fixed_code)
)

Expand All @@ -598,9 +596,9 @@ def test_repeat_repair_too_many_indents(self):
print('repair')
print('me')""")

self.multi_level_tester(
self.single_level_tester(
code=code,
exception=hedy.exceptions.IndentationException,
exception=hedy.exceptions.TooManyIndentsStartLevelException,
extra_check_function=(lambda x: x.exception.fixed_code == fixed_code)
)

Expand All @@ -609,9 +607,9 @@ def test_unexpected_indent(self):
print('repair')
print('me')""")

self.multi_level_tester(
self.single_level_tester(
code=code,
exception=hedy.exceptions.IndentationException
exception=hedy.exceptions.TooManyIndentsStartLevelException
)

def test_repeat_turtle(self):
Expand Down Expand Up @@ -916,7 +914,7 @@ def test_repeat_if_gives_error(self):
prijs is prijs + 1
print 'Dat is in totaal ' prijs ' euro.'""")

self.single_level_tester(code=code, exception=hedy.exceptions.LockedLanguageFeatureException)
self.single_level_tester(code=code, exception=hedy.exceptions.TooManyIndentsStartLevelException)

def test_if_repeat_gives_error(self):
code = textwrap.dedent("""\
Expand All @@ -925,7 +923,7 @@ def test_if_repeat_gives_error(self):
repeat 3 times
print 'mooi'""")

self.single_level_tester(code=code, exception=hedy.exceptions.LockedLanguageFeatureException)
self.single_level_tester(code=code, exception=hedy.exceptions.TooManyIndentsStartLevelException)

#
# if pressed tests
Expand Down Expand Up @@ -1103,16 +1101,14 @@ def test_if_pressed_missing_else_gives_error(self):
max_level=14
)

def test_if_no_indent_after_pressed_and_else_gives_noindent_error(self):
def test_if_no_indent_after_pressed_and_else_gives_error(self):
code = textwrap.dedent("""\
if x is pressed
print 'no indent!'
else
print 'no indent again!'""")

# gives the right exception for all levels even though it misses brackets
# because the indent check happens before parsing
self.multi_level_tester(code=code, exception=hedy.exceptions.NoIndentationException)
self.single_level_tester(code=code, exception=hedy.exceptions.TooFewIndentsStartLevelException)

#
# button tests
Expand Down
84 changes: 84 additions & 0 deletions tests/test_level/test_level_09.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,40 @@ def test_if_else_statements_nested_in_if_else(self):

self.multi_level_tester(code=code, expected=expected, max_level=11)

def test_if_else_no_indentation(self):
code = textwrap.dedent("""\
antwoord is ask Hoeveel is 10 keer tien?
if antwoord is 100
print 'goed zo'
else
print 'bah slecht'""")

# gives the right exception for all levels even though it misses brackets
# because the indent check happens before parsing
self.multi_level_tester(code=code,
exception=hedy.exceptions.NoIndentationException)

def test_if_no_indent_after_pressed_and_else_gives_error(self):
code = textwrap.dedent("""\
if x is pressed
print 'no indent!'
else
print 'no indent again!'""")

# gives the right exception for all levels even though it misses brackets
# because the indent check happens before parsing
self.multi_level_tester(code=code, exception=hedy.exceptions.NoIndentationException)

def test_if_no_indentation(self):
code = textwrap.dedent("""\
antwoord is ask Hoeveel is 10 keer tien?
if antwoord is 100
print 'goed zo'""")

# gives the right exception for all levels even though it misses brackets
# because the indent check happens before parsing
self.multi_level_tester(code=code, exception=hedy.exceptions.NoIndentationException)

#
# repeat nesting
#
Expand All @@ -131,6 +165,46 @@ def test_repeat_nested_in_repeat(self):

self.multi_level_tester(code=code, expected=expected, max_level=11)

def test_repeat_no_indentation(self):
code = textwrap.dedent("""\
repeat 3 times
print 'hooray!'""")

self.multi_level_tester(code=code, exception=hedy.exceptions.NoIndentationException)

def test_repeat_repair_too_few_indents(self):
code = textwrap.dedent("""\
repeat 5 times
print('repair')
print('me')""")

fixed_code = textwrap.dedent("""\
repeat 5 times
print('repair')
print('me')""")

self.multi_level_tester(
code=code,
exception=hedy.exceptions.NoIndentationException,
extra_check_function=(lambda x: x.exception.fixed_code == fixed_code)
)

def test_repeat_repair_too_many_indents(self):
code = textwrap.dedent("""\
repeat 5 times
print('repair')
print('me')""")
fixed_code = textwrap.dedent("""\
repeat 5 times
print('repair')
print('me')""")

self.multi_level_tester(
code=code,
exception=hedy.exceptions.IndentationException,
extra_check_function=(lambda x: x.exception.fixed_code == fixed_code)
)

#
# if and repeat nesting
#
Expand Down Expand Up @@ -306,6 +380,16 @@ def test_if_button_is_pressed_print_in_repeat(self):

self.multi_level_tester(code=code, expected=expected, max_level=11)

def test_unexpected_indent(self):
code = textwrap.dedent("""\
print('repair')
print('me')""")

self.multi_level_tester(
code=code,
exception=hedy.exceptions.IndentationException
)

def test_source_map(self):
code = textwrap.dedent("""\
repeat 3 times
Expand Down
Loading

0 comments on commit c4db1f6

Please sign in to comment.