Skip to content

Commit

Permalink
[Language Idea] Add pressed for binding keyboard events (#3483)
Browse files Browse the repository at this point in the history
Makes it possible to test if a certain keyboard button is pressed.

**Description**
Fixes #3337, #3413, #3406 and #3546.

- Adds the **ifpressed** grammer rule, for level 5 and upwards
- Adds the **UsesPygame** Transformer
- Uses the PyGame library - #3335 

**How to test**
Open up level 5 and use the following snippet

```python
if x is pressed print 'Ouch!' else print 'Hi!'
```
This will map the keyboard press _x_ to print 'Ouch' and any other to 'Hi!'. You can change _x_ by any Latin letter or one digit number. 
After running the code, if you press _x_ it should output 'Ouch!'. The program should stop executing after the output.

![Hedy_—_Mozilla_Firefox_2022-10-25_11-50-32_AdobeExpress(1)](https://user-images.githubusercontent.com/48225550/197743506-64076374-8110-4ee8-ac9f-52eba1883388.gif)

Next, Open up level 8 and use the following snippet
```python
if a is pressed
    print 'Ouch!'
else
    print 'Hi!'
```
This is necessary because in level 8, inline if statements are not allowed anymore. The result should be the same as in level 5.

Try out some turtle commands as well!
```python
if x is pressed forward 50 else turn 90
```
It should get the turtle moving or turning.


**:exclamation: Important Comments**

- The keyword _pressed_ is currently not highlighted. Essentially pressed is a state (for kids: "a special variable") and not a command. I think it would be cool to give these "special variables" a different color (blue maybe?).
  • Loading branch information
ToniSkulj authored Nov 13, 2022
1 parent 273268f commit c2994cc
Show file tree
Hide file tree
Showing 29 changed files with 1,515 additions and 168 deletions.
13 changes: 9 additions & 4 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,13 @@ def parse():
exception = ex
try:
response['Code'] = transpile_result.code

if transpile_result.has_pygame:
response['has_pygame'] = True

if transpile_result.has_turtle:
response['has_turtle'] = True

except Exception as E:
pass
try:
Expand Down Expand Up @@ -1071,7 +1076,7 @@ def get_certificate_page(username):
user = DATABASE.user_by_username(username)
if not user:
return utils.error_page(error=403, ui_message=gettext('user_inexistent'))
progress_data = DATABASE.progress_by_username(username)
progress_data = DATABASE.progress_by_username(username)
if progress_data is None:
return utils.error_page(error=404, ui_message=gettext('no_certificate'))
achievements = progress_data.get('achieved', None)
Expand All @@ -1083,11 +1088,11 @@ def get_certificate_page(username):
count_programs = 0
quiz_score = get_highest_quiz_score(username)
longest_program = get_longest_program(username)

number_achievements = len(achievements)
congrats_message = gettext('congrats_message').format(**{'username': username})
return render_template("certificate.html", count_programs=count_programs, quiz_score=quiz_score,
longest_program=longest_program, number_achievements=number_achievements,
return render_template("certificate.html", count_programs=count_programs, quiz_score=quiz_score,
longest_program=longest_program, number_achievements=number_achievements,
congrats_message=congrats_message)

def get_highest_quiz_score(username):
Expand Down
3 changes: 2 additions & 1 deletion content/keywords/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,5 @@ length: length
9: '9'
0: '0'
comma: ','
quote: "'"
quote: "'"
pressed: pressed
1 change: 1 addition & 0 deletions content/keywords/nl.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ length: lengte
0: '0'
comma: ','
quote: "'"
pressed: ingedrukt
1 change: 1 addition & 0 deletions grammars/keywords-en.lark
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ _OR: _SPACE ("or" | "or") _SPACE
_WHILE: ("while" | "while") _SPACE
_LENGTH: "length" | "length"
_COLOR : ("color" | "color") _SPACE?
_PRESSED: ("pressed" | "pressed") _SPACE?
1 change: 1 addition & 0 deletions grammars/keywords-template.lark
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ _OR: _SPACE ({or} | "or") _SPACE
_WHILE: ({while} | "while") _SPACE
_LENGTH: {length} | "length"
_COLOR : ({color} | "color") _SPACE?
_PRESSED: ({pressed} | "pressed") _SPACE?
1 change: 1 addition & 0 deletions grammars/level1.lark
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ NAME: LETTER_OR_UNDERSCORE LETTER_OR_NUMERAL*

LETTER_OR_UNDERSCORE: /[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}_]+/
LETTER_OR_NUMERAL: LETTER_OR_UNDERSCORE | /[\p{Mn}\p{Mc}\p{Nd}\p{Pc}·]+/
SMALL_LETTER_OR_NUMERAL: /[a-z]/ | /[0-9]/

// Internal symbol added by the preprocess_blocks function to indicate the end of blocks
_END_BLOCK: "end-block"
3 changes: 3 additions & 0 deletions grammars/level17-Additions.lark
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
command:+= ifs (elifs)* elses? -= ifs elses?
// These will be handled by the preprocessor step in the merger
// It will find the appropiate function for this anotation and modify it accordingly
ifpressed_else<needs_colon>
ifpressed<needs_colon>

ifs<needs_colon>
elses<needs_colon>
elifs: _EOL _ELIF _conditions _COLON _EOL (_SPACE command) (_EOL _SPACE command)* _EOL _END_BLOCK
Expand Down
7 changes: 5 additions & 2 deletions grammars/level5-Additions.lark
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ _empty_program: (_EOL | _SPACE)*
_non_empty_program: _EOL* (command | error_invalid) _SPACE* (_EOL+ command _SPACE*)* _EOL* //lines may end on spaces and might be separated by many newlines

//placing assign after print means print is will print 'is' and print is Felienne will print 'is Felienne'
command:+= ifelse | ifs | list_access_var -= error_invalid | error_ask_no_quotes > assign
command:+= ifpressed_else | ifpressed | ifelse | ifs | list_access_var -= error_invalid | error_ask_no_quotes > assign
_if_less_command: print | ask | turtle | assign_list | add | remove | sleep | error_print_no_quotes | list_access_var | assign

// error_invalid is moved from to command to program, so that command rules have priority over error_invalid
Expand All @@ -17,6 +17,9 @@ assign: var _IS textwithspaces
error_print_no_quotes: _PRINT (textwithoutspaces | list_access | var_access) (_SPACE (textwithoutspaces | list_access | var_access))* -> error_print_nq

// new commands for level 5
ifpressed_else: _IF SMALL_LETTER_OR_NUMERAL _IS _PRESSED _EOL* _if_less_command (_SPACE+ _EOL* | _SPACE* _EOL+) _ELSE (_SPACE+ _EOL* | _SPACE* _EOL+) _if_less_command
ifpressed: _IF SMALL_LETTER_OR_NUMERAL _IS _PRESSED _EOL* _if_less_command

_if_clause: _IF (condition (_SPACE+ _EOL* | _SPACE* _EOL+) | condition_spaces _SPACE* _EOL+ | error_condition) _if_less_command
error_condition: condition_spaces _SPACE
ifelse: _if_clause (_SPACE+ _EOL* | _SPACE* _EOL+) _ELSE (_SPACE+ _EOL* | _SPACE* _EOL+) _if_less_command
Expand All @@ -31,6 +34,7 @@ in_list_check: textwithoutspaces _IN var_access

nospace: /[^\n, ]/


textwithspaces: /(?:[^#\n،,, ]| (?!else|başka|अन्यथा|否则|senão|ellers|alie|иначе|altrimenti|annars|anders|ndryshe|inaczej|sinon|sonst|sino|אחרת|وإلا))+/ -> text //anything can be parsed except for a newline and a comma for list separators
//a space is allowed, but it may not be followed by an else. The part " (?!else))" means space not followed by (negative look ahead) else
//That is because allowing else in strings leads to issue #303
Expand All @@ -40,4 +44,3 @@ textwithoutspaces: /(?:[^#\n،,, *+\-\/eiиansbअ否אو]|א(?!חרת )|و(?!


//

2 changes: 1 addition & 1 deletion grammars/level6-Additions.lark
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ _print_argument: (_SPACE | quoted_text | list_access | expression | print_expres
?print_expression: var_access_print | error_unsupported_number | INT

// redefining it entirely since it has many order-depending rules
command: print | turtle | add | remove | sleep | error_print_no_quotes | ifelse | ifs | ask | list_access_var | assign | assign_list | error_invalid_space | error_text_no_print | empty_line
command: print | turtle | add | remove | sleep | error_print_no_quotes | ifpressed_else | ifpressed | ifelse | ifs | ask | list_access_var | assign | assign_list | error_invalid_space | error_text_no_print | empty_line
_if_less_command: print | turtle | add | remove | sleep | error_print_no_quotes | ask | list_access_var | assign | assign_list

//splitting these commands into two rules, one for equals and one for is so they can be properly handled in the translator
Expand Down
7 changes: 5 additions & 2 deletions grammars/level8-Additions.lark
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
command:+= ifs elses?
command:+= ifpressed ifpressed_elses? | ifs elses?

repeat: _REPEAT (INT | var_access) _TIMES _SPACE? _EOL (_SPACE command) (_EOL _SPACE command)* _EOL _END_BLOCK

Expand All @@ -7,8 +7,11 @@ repeat: _REPEAT (INT | var_access) _TIMES _SPACE? _EOL (_SPACE command) (_EOL _S
condition: equality_check | in_list_check
equality_check: (textwithoutspaces | NUMBER) (_IS | _EQUALS) (textwithoutspaces | NUMBER) (_SPACE | textwithoutspaces | NUMBER)*


// from level 8 on ifpressed is implemented slightly differently
ifpressed: _IF SMALL_LETTER_OR_NUMERAL _IS _PRESSED _EOL (_SPACE command) (_EOL _SPACE command)* _EOL _END_BLOCK
ifpressed_else: _IF SMALL_LETTER_OR_NUMERAL _IS _PRESSED _EOL (_SPACE command) (_EOL _SPACE command)* _EOL (_SPACE)* _ELSE (_SPACE)* _EOL (_SPACE command) (_EOL _SPACE command)* _EOL _END_BLOCK
// from level 8 on if is implemented slightly differently
ifpressed_elses: elses
elses: _EOL (_SPACE)* _ELSE (_SPACE)* _EOL (_SPACE command) (_EOL _SPACE command)* _EOL _END_BLOCK
//'if' cannot be used in Python, hence the name of the rule is 'ifs'
ifs: _IF condition _EOL (_SPACE command) (_EOL _SPACE command)* _EOL _END_BLOCK
Loading

0 comments on commit c2994cc

Please sign in to comment.