Added function scope support to interpreter

This commit is contained in:
weckyy702
2020-12-28 00:36:38 +01:00
parent 00a897a897
commit e9ce5d8d93
4 changed files with 133 additions and 99 deletions

5
.gitignore vendored
View File

@@ -1,7 +1,7 @@
__pycache__/ __pycache__/
res/output/ res/output/
res/input/* res/input/
.vscode/* .vscode/
*.json *.json
*.pyc *.pyc
*.png *.png
@@ -9,4 +9,3 @@ debug.py
build/ build/
run.spec run.spec
dist/ dist/
.vscode/launch.json

2
.vscode/launch.json vendored
View File

@@ -8,7 +8,7 @@
"name": "Python: Aktuelle Datei", "name": "Python: Aktuelle Datei",
"type": "python", "type": "python",
"request": "launch", "request": "launch",
"program": "run.py", "program": "debug.py",
"console": "integratedTerminal" "console": "integratedTerminal"
} }
] ]

View File

@@ -1,21 +1,28 @@
import logging import logging
from os import remove from os import remove
import re import re
from typing import Callable, List, Tuple from typing import List, Tuple
from multiprocessing import cpu_count
from multiprocessing.pool import Pool
from errors.custom import InterpreterException, JavaSyntaxError, ScopeNotFoundException from errors.custom import InterpreterException, JavaSyntaxError, ScopeNotFoundException
from draw.Iinstruction import * from draw.Iinstruction import *
COMMENT_REGEX = r"""^//|^#|^COMMENT|^--""" COMMENT_PATTERN = re.compile(r"""^//|^/\*\*|^\*|^--""")
REMOVE_KEYWORDS = [' ', "public", "private", "void", ';'] REMOVE_KEYWORDS = [' ', "public", "private", ';']
FUNCTION_IDENTIFIERS = ["void", "boolean", "int"] #possible return types of functions FUNCTION_IDENTIFIERS = ["void", "boolean", "int", "float"]
WHILE_TAG = "solange " #german for 'while'. Change this depending on your language WHILE_TAG = "solange " #german for 'while'. Change this depending on your language
REPLACE = dict((re.escape(k), '') for k in REMOVE_KEYWORDS) REPLACE = dict((re.escape(k), '') for k in REMOVE_KEYWORDS)
remove_pattern = re.compile("|".join(REPLACE.keys())) remove_pattern = re.compile("|".join(REPLACE.keys()))
function_pattern = re.compile(r"""(?=.*).*\(\)""".join(FUNCTION_IDENTIFIERS)) function_regex = "^("
for kw in FUNCTION_IDENTIFIERS:
function_regex += fr"""{kw}|"""
function_regex = function_regex[0:-1]+ r""").*([(].*[)].*)"""
function_pattern = re.compile(function_regex)
logging.warn("""The Interpreter is WIP and cannot interpret classes or function definitions logging.warn("""The Interpreter is WIP and cannot interpret classes or function definitions
as those do not exist in Nass-Shneidermann Diagrams. A fix is in the making as those do not exist in Nass-Shneidermann Diagrams. A fix is in the making
@@ -31,7 +38,7 @@ def load_src(filepath: str) -> List[str]:
with open(filepath, encoding="utf-8") as file: with open(filepath, encoding="utf-8") as file:
for _line in file: for _line in file:
line = replace_all_tags(_line.strip()) line = replace_all_tags(_line.strip())
if line and not re.match(COMMENT_REGEX, line): if line and not COMMENT_PATTERN.match(line):
lines.append(line) lines.append(line)
if line.__contains__('{'): if line.__contains__('{'):
brace_open_count += 1 brace_open_count += 1
@@ -71,6 +78,17 @@ def get_scope_start_offset(src: List[str], i: int) -> int:
return 2 return 2
raise ScopeNotFoundException("Unable to find scope start. Is the program ill-formed?") raise ScopeNotFoundException("Unable to find scope start. Is the program ill-formed?")
def get_scope_exit_offset(src: List[str], start_idx: int) -> int:
i = start_idx
while i < len(src):
line = src[i]
if "{" in line:
i+= get_scope_exit_offset(src, i+1)
elif "}" in line:
return i-start_idx
i+=1
def handle_while(line: str, src: List[str], i: int) -> Tuple[Iinstruction, int]: def handle_while(line: str, src: List[str], i: int) -> Tuple[Iinstruction, int]:
bracket_idx = line.rindex(')') # throws if while contruct is illformed bracket_idx = line.rindex(')') # throws if while contruct is illformed
@@ -162,25 +180,40 @@ def get_instructions_in_scope(src: List[str], start_idx: int = 0) -> Tuple[List[
return outer_scope, i return outer_scope, i
def get_function_scopes(src: List[str]) -> List[Tuple[int, int]]: def get_function_scope_spans(src: List[str]) -> List[Tuple[int, int]]:
spans = []
i = 0 i = 0
print(function_pattern)
while i < len(src): while i < len(src):
line = src[i] line = src[i]
try: try:
if function_pattern.match(line): if match:= function_pattern.match(line):
print(line) groups = match.groups()
function_name = line.removeprefix(groups[0]).removesuffix(groups[1])
brace_offset = get_scope_start_offset(src, i)
scope_offset = get_scope_exit_offset(src, i+brace_offset)
span = (i+brace_offset, i+brace_offset+scope_offset)
i += scope_offset + brace_offset
spans.append(span)
except: except Exception as e:
logging.error("encountered error in line %i : %s", i, str(e))
raise raise
i += 1 i += 1
return [(0, 0)] return spans
def load_instructions(filepath: str) -> List[Iinstruction]: def scope_handler (int_info: Tuple[List[str], Tuple[int, int]]) -> List[Iinstruction]:
src = load_src(filepath) return get_instructions_in_scope(int_info[0][int_info[1][0]: int_info[1][1]])[0]
instructions, i = get_instructions_in_scope(src)
if i != len(src): def get_instructions_in_scopes(src: List[str], scope_spans: List[Tuple[int, int]]):
raise InterpreterException("Unknown error during source interpretation! Unsupported language constructs or ill-formed source?") p = Pool(processes=cpu_count())
instructions = list(map(scope_handler, [(src, scope_span) for scope_span in scope_spans]))#p.map(scope_handler, [(src, scope_span) for scope_span in scope_spans])
return instructions
def load_instructions(filepath: str) -> List[List[Iinstruction]]:
src = load_src(filepath)
scope_spans = get_function_scope_spans(src)
instructions = get_instructions_in_scopes(src, scope_spans)
return instructions return instructions

View File

@@ -1,83 +1,85 @@
beforeIf(); public void act()
if(if_condition1) {
true_case;
true_case;
}
afterIf();
beforeIf();
if(if_condition2)
{ {
true_case; S66Nr3(7);
true_case;
}
afterIf();
beforeIf();
if(if_else_condition1) {
true_case;
true_case;
} else {
false_case;
false_case;
}
afterIf();
beforeIf();
if(if_else_condition2) {
true_case;
true_case;
}
else {
false_case;
false_case;
}
afterIf();
beforeIf();
if(if_else_condition3) {
true_case;
true_case;
}
else
{
false_case;
false_case;
}
afterIf();
beforeWhile();
while(while_condition1) {
insideWhile;
insideWhile;
}
beforeWhile();
while(while_condition2)
{
insideWhile;
insideWhile;
}
beforeDoWhile();
do{
insideDoWhile;
insideDoWhile;
}while(do_while_condition1);
beforeDoWhile();
do
{
insideDoWhile;
insideDoWhile;
}while(do_while_condition2);
beforeDoWhile();
do
{
insideDoWhile;
insideDoWhile;
}
while(do_while_condition3)
//since the interpreter ignores all empty lines and spaces, any changes in tabs *should* not have any effect
void function1() {
} }
boolean function2() private void fahreUmHuegel(String richtung)
{ {
String pri;
String sec;
if(richtung.equals("Hoch")) {
pri = "links";
sec = "rechts";
} else {
if (richtung.equals("Runter")){
pri = "rechts";
sec = "links";
} else {
nachricht("JUNGE DU SPAST!");
return;
}
}
drehe(pri);
fahre();
drehe(sec);
fahre();
fahre();
drehe(sec);
fahre();
drehe(pri);
}
private void fahreBisHuegel()
{
while(!huegelVorhanden("vorne"))
{
fahre();
}
}
private void fahreZeileDreheHoch()
{
fahreBisHuegel();
fahreUmHuegel("Hoch");
fahreBisHuegel();
drehe("um");
fahreBisHuegel();
fahreUmHuegel("Runter");
fahreBisHuegel();
drehe("rechts");
fahre();
drehe("rechts");
}
private void fahreZeileDreheRunter(boolean geheInNächsteZeile)
{
fahreBisHuegel();
fahreUmHuegel("Runter");
fahreBisHuegel();
drehe("um");
fahreBisHuegel();
fahreUmHuegel("Hoch");
fahreBisHuegel();
if(geheInNächsteZeile) {
drehe("rechts");
fahre();
drehe("rechts");
} else {
drehe("um");
}
}
private void S66Nr3(int anzahlZeilen)
{
if(anzahlZeilen < 3) {
nachricht("Ich muss mindestens drei Zeilen fahren! :(");
return;
}
fahreZeileDreheHoch();
for(int i = 1; i < anzahlZeilen-1; i++) {
fahreZeileDreheRunter(true);
}
fahreZeileDreheRunter(false);
} }