Compare commits
	
		
			No commits in common. "c00f788d2756d7fff80a50f166f4f62d0355c4f2" and "c8ad44e93ed9a2b01110de44947817ed0f19719c" have entirely different histories. 
		
	
	
		
			c00f788d27
			...
			c8ad44e93e
		
	
		
							
								
								
									
										278
									
								
								lambdaV.py
								
								
								
								
							
							
						
						
									
										278
									
								
								lambdaV.py
								
								
								
								
							|  | @ -15,34 +15,26 @@ | |||
| # version 3 along with this program. | ||||
| # If not, see https://www.gnu.org/licenses/gpl-3.0.en.html | ||||
| 
 | ||||
| import re, time | ||||
| import re | ||||
| 
 | ||||
| debug_mode = False | ||||
| debug_mode = True | ||||
| 
 | ||||
| def debug_message(text): | ||||
|     if debug_mode: | ||||
|         print("DEBUG: ", end="") | ||||
|         print(text) | ||||
| cursor_up    = 'Λ' | ||||
| cursor_down  = 'V' | ||||
| cursor_left  = '<' | ||||
| cursor_right = '>' | ||||
| 
 | ||||
| 
 | ||||
| cursor_north = 'Λ' | ||||
| cursor_south = 'V' | ||||
| cursor_west  = '<' | ||||
| cursor_east  = '>' | ||||
| 
 | ||||
| cursor_current = ' ' | ||||
| 
 | ||||
| field = [ | ||||
|     " _________________ ", | ||||
|     "|                 |", | ||||
|     "|                 |", | ||||
|     "|                 |", | ||||
|     "|                 |", | ||||
|     "|                 |", | ||||
|     "|                 |", | ||||
|     "|                 |", | ||||
|     "|                 |", | ||||
|     " ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ " | ||||
| empty_field = [ | ||||
|     " ________________ ", | ||||
|     "|                |", | ||||
|     "|                |", | ||||
|     "|                |", | ||||
|     "|                |", | ||||
|     "|                |", | ||||
|     "|                |", | ||||
|     "|                |", | ||||
|     "|                |", | ||||
|     " ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ " | ||||
| ] | ||||
| 
 | ||||
| wall  = '#' | ||||
|  | @ -51,167 +43,58 @@ goal  = '$' | |||
| 
 | ||||
| cursor_position = [0, 0] | ||||
| 
 | ||||
| command_delay = 0.3 | ||||
| 
 | ||||
| def clear_field(): | ||||
|     field = [ | ||||
|         " _________________ ", | ||||
|         "|                 |", | ||||
|         "|                 |", | ||||
|         "|                 |", | ||||
|         "|                 |", | ||||
|         "|                 |", | ||||
|         "|                 |", | ||||
|         "|                 |", | ||||
|         "|                 |", | ||||
|         " ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ " | ||||
|     ] | ||||
| 
 | ||||
| def draw_field(): | ||||
|     print("\033[2J\033[H") | ||||
|     for row in range(len(field)): | ||||
|         for column in range(len(field[row])): | ||||
|             if column==cursor_position[0] and row==cursor_position[1]: | ||||
|                 print(cursor_current, end="") | ||||
|             else: | ||||
|                 print(field[row][column], end="") | ||||
|         print("") | ||||
| 
 | ||||
| 
 | ||||
| # returns "" or error message | ||||
| # Parsed code is the result of running the parser, | ||||
| # though at this point the input is assumed to be valid | ||||
| # and no additional checks are performed on what the parser produced. | ||||
| def run_code(parsed_code): | ||||
|     for i in range(len(parsed_code[0])): | ||||
|         result = parsed_code[0][i](*parsed_code[1][i]) | ||||
|         if not result=="": | ||||
|             return result | ||||
|         draw_field() | ||||
|         time.sleep(command_delay) | ||||
|     return "" | ||||
| 
 | ||||
| 
 | ||||
| def condition_facing_north(inverted): | ||||
|     if inverted: | ||||
|         return not cursor_current == cursor_north | ||||
|     return cursor_current == cursor_north | ||||
| 
 | ||||
| def condition_facing_south(inverted): | ||||
|     if inverted: | ||||
|         return not cursor_current == cursor_south | ||||
|     return cursor_current == cursor_south | ||||
| 
 | ||||
| def condition_facing_east(inverted): | ||||
|     if inverted: | ||||
|         return not cursor_current == cursor_east | ||||
|     return cursor_current == cursor_east | ||||
| 
 | ||||
| def condition_facing_west(inverted): | ||||
|     if inverted: | ||||
|         return not cursor_current == cursor_west | ||||
|     return cursor_current == cursor_west | ||||
| def debug_message(text): | ||||
|     if debug_mode: | ||||
|         print("DEBUG: ", end="") | ||||
|         print(text) | ||||
| 
 | ||||
| def condition_in_front_of_wall(inverted): | ||||
|     if condition_facing_north(False): | ||||
|         result = field[cursor_position[1]-1][cursor_position[0]]==wall or field[cursor_position[1]-1][cursor_position[0]]=='_' | ||||
|     elif condition_facing_south(False): | ||||
|         result = field[cursor_position[1]+1][cursor_position[0]]==wall or field[cursor_position[1]+1][cursor_position[0]]=='¯' | ||||
|     elif condition_facing_east(False): | ||||
|         result = field[cursor_position[1]][cursor_position[0]+1]==wall or field[cursor_position[1]][cursor_position[0]+1]=='|' | ||||
|     elif condition_facing_west(False): | ||||
|         result = field[cursor_position[1]][cursor_position[0]-1]==wall or field[cursor_position[1]][cursor_position[0]-1]=='|' | ||||
|     else: | ||||
|         result = False | ||||
|     if inverted: | ||||
|         return not result | ||||
|     return result | ||||
|     return False | ||||
| 
 | ||||
| def condition_goal_reached(inverted): | ||||
|     if inverted: | ||||
|         return not field[cursor_position[1]][cursor_position[0]]==goal | ||||
|     return field[cursor_position[1]][cursor_position[0]]==goal | ||||
|     return False | ||||
| 
 | ||||
| def condition_on_apple(inverted): | ||||
|     if inverted: | ||||
|         return not field[cursor_position[1]][cursor_position[0]]==apple | ||||
|     return field[cursor_position[1]][cursor_position[0]]==apple | ||||
|     return False | ||||
| 
 | ||||
| def condition_facing_north(inverted): | ||||
|     return False | ||||
| 
 | ||||
| def condition_facing_south(inverted): | ||||
|     return False | ||||
| 
 | ||||
| def condition_facing_east(inverted): | ||||
|     return False | ||||
| 
 | ||||
| def condition_facing_west(inverted): | ||||
|     return False | ||||
| 
 | ||||
| # condition prefixed with ! | ||||
| def modifier_not(condition): | ||||
|     return condition(true) | ||||
| 
 | ||||
| # return value: "" or error message | ||||
| def command_step(): | ||||
|     if condition_in_front_of_wall(False): | ||||
|         return "You stepped into a wall." | ||||
| 
 | ||||
|     if condition_facing_north(False): | ||||
|         cursor_position[1] = cursor_position[1]-1 | ||||
|     elif condition_facing_south(False): | ||||
|         cursor_position[1] = cursor_position[1]+1 | ||||
|     elif condition_facing_east(False): | ||||
|         cursor_position[0] = cursor_position[0]+1 | ||||
|     elif condition_facing_west(False): | ||||
|         cursor_position[0] = cursor_position[0]-1 | ||||
|     else: | ||||
|         return "Cannot step because direction is unknown." | ||||
|     #TODO | ||||
|     return "" | ||||
| 
 | ||||
| def command_left(): | ||||
|     global cursor_current | ||||
|     if condition_facing_north(False): | ||||
|         cursor_current = cursor_west | ||||
|     elif condition_facing_south(False): | ||||
|         cursor_current = cursor_east | ||||
|     elif condition_facing_east(False): | ||||
|         cursor_current = cursor_north | ||||
|     elif condition_facing_west(False): | ||||
|         cursor_current = cursor_south | ||||
|     else: | ||||
|         return "Cannot turn left because direction is unknown." | ||||
|     return "" | ||||
| 
 | ||||
| def command_right(): | ||||
|     global cursor_current | ||||
|     if condition_facing_north(False): | ||||
|         cursor_current = cursor_east | ||||
|     elif condition_facing_south(False): | ||||
|         cursor_current = cursor_west | ||||
|     elif condition_facing_east(False): | ||||
|         cursor_current = cursor_south | ||||
|     elif condition_facing_west(False): | ||||
|         cursor_current = cursor_north | ||||
|     else: | ||||
|         return "Cannot turn right because direction is unknown." | ||||
|     return "" | ||||
| 
 | ||||
| def command_take(): | ||||
|     if condition_on_apple(True): | ||||
|         # Note: condition is inverted | ||||
|         return "Cannot take apple, there is no apple here." | ||||
|     field[cursor_position[1]] = field[cursor_position[1]][:cursor_position[0]]+" "+field[cursor_position[1]][cursor_position[0]+1:] | ||||
|     return "" | ||||
| 
 | ||||
| def command_repeat(number, parsed_code): | ||||
|     for i in range(number): | ||||
|         result = run_code(parsed_code) | ||||
|         if not result=="": | ||||
|             return result | ||||
|     return "" | ||||
| 
 | ||||
| def command_while(parsed_condition, parsed_code): | ||||
|     while parsed_condition[0](parsed_condition[1]): | ||||
|         result = run_code(parsed_code) | ||||
|         if not result=="": | ||||
|             return result | ||||
|     return "" | ||||
| 
 | ||||
| def command_take(): | ||||
|     return "" | ||||
| 
 | ||||
| def command_if(parsed_condition, parsed_then_code, parsed_else_code): | ||||
|     if parsed_condition[0](parsed_condition[1]): | ||||
|         result = run_code(parsed_then_code) | ||||
|         if not result=="": | ||||
|             return result | ||||
|     elif not parsed_else_code==None: | ||||
|         result = run_code(parsed_else_code) | ||||
|         if not result=="": | ||||
|             return result | ||||
|     return "" | ||||
| 
 | ||||
| 
 | ||||
|  | @ -313,7 +196,7 @@ def parse_code(code, allowed_commands, allowed_conditions, unformatted_code=True | |||
|         debug_message("Formatted code: "+code) | ||||
| 
 | ||||
|     parse_position = 0 | ||||
|     parsed_code = [[], [], -1, "", code] | ||||
|     parsed_code = [[], [], -1, ""] | ||||
|     while parse_position < len(code): | ||||
|         # find next command | ||||
|         next_space = code.find(' ', parse_position) | ||||
|  | @ -338,16 +221,16 @@ def parse_code(code, allowed_commands, allowed_conditions, unformatted_code=True | |||
|             elif next_command == "take": | ||||
|                 parsed_code[0].append(command_take) | ||||
|             elif next_command == "repeat": | ||||
|                 return [[], [], next_space, "Syntax error: Number of repetitions missing", code] | ||||
|                 return [[], [], next_space, "Syntax error: Condition missing"] | ||||
|             elif next_command == "while": | ||||
|                 return [[], [], next_space, "Syntax error: Condition missing", code] | ||||
|                 return [[], [], next_space, "Syntax error: Condition missing"] | ||||
|             elif next_command == "if": | ||||
|                 return [[], [], next_space, "Syntax error: Condition missing", code] | ||||
|             elif next_command[0:4] == "else": | ||||
|                 return [[], [], parse_position, "Syntax error: Else without if statement", code] | ||||
|                 return [[], [], next_space, "Syntax error: Condition missing"] | ||||
|             elif next_command == "else": | ||||
|                 return [[], [], parse_position, "Syntax error: Else without if statement"] | ||||
|             else: | ||||
|                 #TODO: better error message (especially when special chars are detected inside next_command or a known command) | ||||
|                 return [[], [], parse_position, "Unknown command: "+next_command, code] | ||||
|                 return [[], [], parse_position, "Unknown command: "+next_command] | ||||
|             parse_position = next_space+1 | ||||
|         else: | ||||
|             debug_message("Found control structure...") | ||||
|  | @ -358,28 +241,28 @@ def parse_code(code, allowed_commands, allowed_conditions, unformatted_code=True | |||
|                 repetitions_length = get_length_of_condition(code[parse_position:]) | ||||
|                 if repetitions_length == -2: | ||||
|                     debug_message("  Mismatched <>") | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find matching '>' for this '<'", code] | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find matching '>' for this '<'"] | ||||
|                 repetitions = code[parse_position:parse_position+repetitions_length] | ||||
|                 debug_message("  Number of repetitions: "+repetitions) | ||||
|                 repetitions_int = 0 | ||||
|                 try: | ||||
|                     repetitions_int = int(repetitions[1:-1]) | ||||
|                 except ValueError: | ||||
|                     return [[], [], parse_position, "Not a valid number: "+repetitions[1:-1], code] | ||||
|                     return [[], [], parse_position, "Not a valid number: "+repetitions[1:-1]] | ||||
|                 parse_position = parse_position+len(repetitions) | ||||
|                 contained_code_length = get_length_of_contained_code(code[parse_position:]) | ||||
|                 if contained_code_length == -1: | ||||
|                     debug_message("  Missing (") | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find '(' for contained code", code] | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find '(' for contained code"] | ||||
|                 if contained_code_length == -2: | ||||
|                     debug_message("  Mismatched ()") | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find matching ')' for this '('", code] | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find matching ')' for this '('"] | ||||
|                 contained_code = code[parse_position:parse_position+contained_code_length] | ||||
|                 debug_message("  Contained code: "+contained_code) | ||||
|                 parsed_contained_code = parse_code(contained_code[1:-1], allowed_commands, allowed_conditions, unformatted_code=False) | ||||
|                 if not parsed_contained_code[2]==-1: | ||||
|                     debug_message("  Error while parsing contained code") | ||||
|                     return [[], [], parse_position+1+parsed_contained_code[2], parsed_contained_code[3], code] | ||||
|                     return [[], [], parse_position+1+parsed_contained_code[2], parsed_contained_code[3]] | ||||
|                 parse_position = parse_position+contained_code_length+1 | ||||
| 
 | ||||
|                 parsed_code[1].append((repetitions_int, parsed_contained_code)) | ||||
|  | @ -391,26 +274,26 @@ def parse_code(code, allowed_commands, allowed_conditions, unformatted_code=True | |||
|                 condition_length = get_length_of_condition(code[parse_position:]) | ||||
|                 if condition_length == -2: | ||||
|                     debug_message("  Mismatched <>") | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find matching '>' for this '<'", code] | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find matching '>' for this '<'"] | ||||
|                 condition = code[parse_position:parse_position+condition_length] | ||||
|                 debug_message("  Condition is: "+condition) | ||||
|                 parsed_condition = parse_condition(condition[1:-1], allowed_conditions) | ||||
|                 if not parsed_condition[2]=="": | ||||
|                     return [[], [], parse_position, parsed_condition[2], code] | ||||
|                     return [[], [], parse_position, parsed_condition[2]] | ||||
|                 parse_position = parse_position+len(condition) | ||||
|                 then_code_length = get_length_of_contained_code(code[parse_position:]) | ||||
|                 if then_code_length == -1: | ||||
|                     debug_message("  Missing (") | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find '(' for then-code", code] | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find '(' for then-code"] | ||||
|                 if then_code_length == -2: | ||||
|                     debug_message("  Mismatched ()") | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find matching ')' for this '('", code] | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find matching ')' for this '('"] | ||||
|                 then_code = code[parse_position:parse_position+then_code_length] | ||||
|                 debug_message("  Then-code: "+then_code) | ||||
|                 parsed_then_code = parse_code(then_code[1:-1], allowed_commands, allowed_conditions, unformatted_code=False) | ||||
|                 if not parsed_then_code[2]==-1: | ||||
|                     debug_message("  Error while parsing then-code") | ||||
|                     return [[], [], parse_position+1+parsed_then_code[2], parsed_then_code[3], code] | ||||
|                     return [[], [], parse_position+1+parsed_then_code[2], parsed_then_code[3]] | ||||
|                 parse_position = parse_position+then_code_length+1 | ||||
|                 parsed_else_code = None | ||||
|                 if parse_position<len(code)+4 and code[parse_position:parse_position+4]=="else": | ||||
|  | @ -418,10 +301,10 @@ def parse_code(code, allowed_commands, allowed_conditions, unformatted_code=True | |||
|                     else_code_length = get_length_of_contained_code(code[parse_position:]) | ||||
|                     if else_code_length == -1: | ||||
|                         debug_message("  Missing (") | ||||
|                         return [[], [], parse_position, "Syntax error: Cannot not find '(' for else-code", code] | ||||
|                         return [[], [], parse_position, "Syntax error: Cannot not find '(' for else-code"] | ||||
|                     if else_code_length == -2: | ||||
|                         debug_message("  Mismatched ()") | ||||
|                         return [[], [], parse_position, "Syntax error: Cannot not find matching ')' for this '('", code] | ||||
|                         return [[], [], parse_position, "Syntax error: Cannot not find matching ')' for this '('"] | ||||
|                     else_code = code[parse_position:parse_position+else_code_length] | ||||
|                     debug_message("  Else-code: "+else_code) | ||||
|                     parsed_else_code = parse_code(else_code[1:-1], allowed_commands, allowed_conditions, unformatted_code=False) | ||||
|  | @ -436,26 +319,26 @@ def parse_code(code, allowed_commands, allowed_conditions, unformatted_code=True | |||
|                 condition_length = get_length_of_condition(code[parse_position:]) | ||||
|                 if condition_length == -2: | ||||
|                     debug_message("  Mismatched <>") | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find matching '>' for this '<'", code] | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find matching '>' for this '<'"] | ||||
|                 condition = code[parse_position:parse_position+condition_length] | ||||
|                 debug_message("  Condition is: "+condition) | ||||
|                 parsed_condition = parse_condition(condition[1:-1], allowed_conditions) | ||||
|                 if not parsed_condition[2]=="": | ||||
|                     return [[], [], parse_position, parsed_condition[2], code] | ||||
|                     return [[], [], parse_position, parsed_condition[2]] | ||||
|                 parse_position = parse_position+len(condition) | ||||
|                 contained_code_length = get_length_of_contained_code(code[parse_position:]) | ||||
|                 if contained_code_length == -1: | ||||
|                     debug_message("  Missing (") | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find '(' for contained code", code] | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find '(' for contained code"] | ||||
|                 if contained_code_length == -2: | ||||
|                     debug_message("  Mismatched ()") | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find matching ')' for this '('", code] | ||||
|                     return [[], [], parse_position, "Syntax error: Cannot not find matching ')' for this '('"] | ||||
|                 contained_code = code[parse_position:parse_position+contained_code_length] | ||||
|                 debug_message("  Contained code: "+contained_code) | ||||
|                 parsed_contained_code = parse_code(contained_code[1:-1], allowed_commands, allowed_conditions, unformatted_code=False) | ||||
|                 if not parsed_contained_code[2]==-1: | ||||
|                     debug_message("  Error while parsing contained code") | ||||
|                     return [[], [], parse_position+1+parsed_contained_code[2], parsed_contained_code[3], code] | ||||
|                     return [[], [], parse_position+1+parsed_contained_code[2], parsed_contained_code[3]] | ||||
|                 parse_position = parse_position+contained_code_length+1 | ||||
| 
 | ||||
|                 parsed_code[1].append((parsed_condition, parsed_contained_code)) | ||||
|  | @ -463,30 +346,13 @@ def parse_code(code, allowed_commands, allowed_conditions, unformatted_code=True | |||
|             else: | ||||
|                 debug_message("  Type: unknown control structure: "+control_structure) | ||||
|                 #TODO: better error message (especially when special chars are detected inside control_structure or a known command) | ||||
|                 return [[], [], parse_position, "Syntax error: Unknown control structure: "+control_structure, code] | ||||
|                 return [[], [], parse_position, "Syntax error: Unknown control structure: "+control_structure] | ||||
|     return parsed_code | ||||
| 
 | ||||
| # A wrapper for run_code that deals with potential errors produced by the parser. | ||||
| # returns success or error message | ||||
| def evaluate_parser_result(parsed_code): | ||||
|     if not parsed_code[2]==-1: | ||||
|         # parser error | ||||
|         return parsed_code[3] + "\n" + (" "*parsed_code[2]) + "↓\n" + parsed_code[4] | ||||
|     outcome = run_code(parsed_code) | ||||
|     if not outcome=="": | ||||
|         # runtime error | ||||
|         # TODO: pass back information about where the error occurred | ||||
|         return outcome | ||||
|     #TODO: check if goal reached | ||||
|     return "Success!" | ||||
| 
 | ||||
| 
 | ||||
| def debug_setup(): | ||||
|     global cursor_position | ||||
|     cursor_position = [1,1] | ||||
|     global cursor_current | ||||
|     cursor_current = cursor_south | ||||
|     draw_field() | ||||
| # Parsed code is the result of running the parser. | ||||
| def run_code(parsed_code): | ||||
|     return "" | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     pass | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue