From e8dfb948608eb7c6c1bfbc5ef45227d6255472a5 Mon Sep 17 00:00:00 2001 From: NikolajDanger Date: Mon, 19 Feb 2024 11:21:07 +0100 Subject: [PATCH] :sparkles: --- .gitignore | 3 +- documentation/plthy.pdf | Bin 13939 -> 22438 bytes documentation/plthy.tex | 23 ++- examples/guessing_game.plthy | 10 + plthy | 2 - plthy_impl/ast_nodes.py | 180 ++++++++++++++++-- plthy_impl/lexer.py | 17 +- plthy_impl/parser.py | 38 +++- test.sh | 28 +++ tests/01_none.expected | 0 tests/{none.plthy => 01_none.plthy} | 0 tests/02_variable.expected | 1 + tests/{variable.plthy => 02_variable.plthy} | 0 tests/03_math.expected | 1 + tests/{math.plthy => 03_math.plthy} | 0 tests/04_scope.expected | 1 + tests/{scope.plthy => 04_scope.plthy} | 0 tests/05_maybe.expected1 | 1 + tests/05_maybe.expected2 | 1 + tests/{maybe.plthy => 05_maybe.plthy} | 0 tests/06_if.expected | 1 + tests/{if.plthy => 06_if.plthy} | 0 tests/07_function.expected | 1 + tests/{function.plthy => 07_function.plthy} | 0 tests/08_precedence.expected | 3 + .../{precedence.plthy => 08_precedence.plthy} | 2 + tests/09_fib.expected | 5 + tests/{fib.plthy => 09_fib.plthy} | 0 tests/10_E001.expected | 1 + tests/10_E001.plthy | 2 + tests/11_E002.expected | 1 + tests/11_E002.plthy | 2 + tests/12_list.expected | 3 + tests/12_list.plthy | 6 + 34 files changed, 295 insertions(+), 38 deletions(-) create mode 100644 examples/guessing_game.plthy create mode 100644 test.sh create mode 100644 tests/01_none.expected rename tests/{none.plthy => 01_none.plthy} (100%) create mode 100644 tests/02_variable.expected rename tests/{variable.plthy => 02_variable.plthy} (100%) create mode 100644 tests/03_math.expected rename tests/{math.plthy => 03_math.plthy} (100%) create mode 100644 tests/04_scope.expected rename tests/{scope.plthy => 04_scope.plthy} (100%) create mode 100644 tests/05_maybe.expected1 create mode 100644 tests/05_maybe.expected2 rename tests/{maybe.plthy => 05_maybe.plthy} (100%) create mode 100644 tests/06_if.expected rename tests/{if.plthy => 06_if.plthy} (100%) create mode 100644 tests/07_function.expected rename tests/{function.plthy => 07_function.plthy} (100%) create mode 100644 tests/08_precedence.expected rename tests/{precedence.plthy => 08_precedence.plthy} (66%) create mode 100644 tests/09_fib.expected rename tests/{fib.plthy => 09_fib.plthy} (100%) create mode 100644 tests/10_E001.expected create mode 100644 tests/10_E001.plthy create mode 100644 tests/11_E002.expected create mode 100644 tests/11_E002.plthy create mode 100644 tests/12_list.expected create mode 100644 tests/12_list.plthy diff --git a/.gitignore b/.gitignore index c40d955..f2d8a4c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ **/*.log **/*.out **/*.synctex.gz -**/*.xdv \ No newline at end of file +**/*.xdv +tests/*.output \ No newline at end of file diff --git a/documentation/plthy.pdf b/documentation/plthy.pdf index abb02c20092dac4129bae721373ef53ed21ce9f1..46b1109b8844f09aea2ba7e2854cd1fad406419f 100644 GIT binary patch delta 15201 zcmaibV{~R+w`FYGwr$&H#kQSF@>Fa-v2EKGRcxCT+o+)H{knhLx9=U@|IS!r?=!|( zd(MTq*SWVZtpi1+RFRNkWM$%nqx^ky`2xqvn}|vY;N@l$5`uGcceOBafb(8o`oWJycJ$;=zN1?ZNKvUL#3!q8E?(74mC6e*;EkD7h?^{miKqWoxDLb97^3^c++o8>CBa6EhpGTWzxD8fQ*KMZAb z0(v$X7H-%o4)F%5anaj~$#^he?x2{t4(ay()lz2m4uES^P<04(SK!mF=6T}|haM#p znT~z>@V2YhS#VB|7&W%CoaACxYp?W3LcmN22$Ld}k%G%lpYKe#-moLJeE)74(*?N( zhy;HSozPkyq_gx4w{Rx}k!4d88PvxF@9kJvU=bN(8R-`^u{QF;g1*Oo>`os>E{S&> zTE(oy2P>WVHqd<3=ip+TVcjDrCk2Y{m1l;^M8?O!>+9H@@) zSV5>y<@3^I$4H|8S*~-{1=-HkAU&rdNv>E>`$RFH;CLlB&MI%0DQ#&(1itx;7pUEv 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 HDY*Xyr*Z}J delta 7066 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 MiVp-n*HXm)Kcx^FcmMzZ diff --git a/documentation/plthy.tex b/documentation/plthy.tex index 05d9301..a6da828 100644 --- a/documentation/plthy.tex +++ b/documentation/plthy.tex @@ -1,5 +1,11 @@ \documentclass[a4paper]{paper} \usepackage[margin=2.5cm]{geometry} +\usepackage{enumitem} + +\def\threedigits#1{% +\ifnum#1<100 0\fi +\ifnum#1<10 0\fi +\number#1} \begin{document} \begin{center} @@ -16,20 +22,33 @@ \textit{statement} & $\rightarrow$ & \textit{statement} \texttt{because} \textit{expression} \\ \hline \textit{statement} & $\rightarrow$ & \texttt{until} \textit{expression} \textit{statement} \\ \hline \textit{statement} & $\rightarrow$ & \textit{expression} \texttt{->} \textbf{id} \\ \hline - \textit{statement} & $\rightarrow$ & \texttt{define} \textbf{function} \texttt{<} \textbf{numeral} \texttt{>} \texttt{as} \textit{statement} \\ \hline + \textit{statement} & $\rightarrow$ & \texttt{define} \textbf{function} \texttt{<} \textbf{int} \texttt{>} \texttt{as} \textit{statement} \\ \hline \textit{statement} & $\rightarrow$ & \texttt{return} \textit{expression} \\ \hline\hline \textit{command} & $\rightarrow$ & \textbf{builtin} \texttt{<} \textit{expressions} \texttt{>} \\ \hline \textit{command} & $\rightarrow$ & \texttt{"} \textbf{function} \texttt{" <} \textit{expressions} \texttt{>} \\ \hline\hline \textit{expressions} & $\rightarrow$ & \\ \hline \textit{expressions} & $\rightarrow$ & \textit{expression} \texttt{;} \textit{expressions} \\ \hline\hline \textit{expression} & $\rightarrow$ & \textbf{string} \\ \hline - \textit{expression} & $\rightarrow$ & \textbf{numeral} \\ \hline + \textit{expression} & $\rightarrow$ & \textbf{int} \\ \hline + \textit{expression} & $\rightarrow$ & \textbf{float} \\ \hline \textit{expression} & $\rightarrow$ & \textbf{boolean} \\ \hline \textit{expression} & $\rightarrow$ & \texttt{\{} \textit{expressions} \texttt{\}} \\ \hline + \textit{expression} & $\rightarrow$ & \textit{expression} \texttt{\{} \textit{expression} \texttt{\}} \\ \hline \textit{expression} & $\rightarrow$ & \texttt{(} \textit{expression} \texttt{)} \\ \hline \textit{expression} & $\rightarrow$ & \textit{expression} \textbf{binop} \textit{expression} \\ \hline \textit{expression} & $\rightarrow$ & \texttt{variable} \textbf{id}\\ \hline \textit{expression} & $\rightarrow$ & \textit{statement} \\ \hline \end{tabular} \end{center} + + \section{Errors} + \begin{enumerate}[label={\textbf{E\protect\threedigits{\theenumi}:}}, leftmargin = *] + \item No greeting + \item No valediction + \item Unexpected token + \item Random compiler error + \item Unknown builtin + \item Wrong number of arguments for builtin + \item Unknown binop + \end{enumerate} \end{document} \ No newline at end of file diff --git a/examples/guessing_game.plthy b/examples/guessing_game.plthy new file mode 100644 index 0000000..687cd9d --- /dev/null +++ b/examples/guessing_game.plthy @@ -0,0 +1,10 @@ +hello| +$do random<1;128;> -> n| +$0 -> guess| +until variable guess = variable n [ + $do input<'guess: ';> -> guess| + do print<'too high';> if variable guess > variable n| + do print<'too low';> if variable guess < variable n| + do print<'correct!';> if variable guess = variable n| +]| +goodbye| \ No newline at end of file diff --git a/plthy b/plthy index d036cea..89afb42 100755 --- a/plthy +++ b/plthy @@ -26,8 +26,6 @@ def main(): parser = Parser() tokens = lexer.lex(program_text) - # for t in tokens: - # print(t) program = parser.parse(tokens) diff --git a/plthy_impl/ast_nodes.py b/plthy_impl/ast_nodes.py index acc2a45..aaf28c6 100644 --- a/plthy_impl/ast_nodes.py +++ b/plthy_impl/ast_nodes.py @@ -16,10 +16,16 @@ class Exp(BaseBox): def eval(self, vtable, ftable): return vtable, ftable, None -class ExpNumeral(Exp): + def __repr__(self) -> str: + return "exp()" + +class ExpInt(Exp): def __init__(self, value: int): self.value = value + def __repr__(self) -> str: + return f"exp_int({self.value})" + def eval(self, vtable, ftable): return vtable, ftable, self.value @@ -27,6 +33,9 @@ class ExpString(Exp): def __init__(self, value: str): self.value = value + def __repr__(self) -> str: + return f"exp_string({self.value})" + def eval(self, vtable, ftable): return vtable, ftable, self.value @@ -34,6 +43,9 @@ class ExpVariable(Exp): def __init__(self, variable_id: str): self.variable_name = variable_id + def __repr__(self) -> str: + return f"exp_variable({self.variable_name})" + def eval(self, vtable, ftable): return vtable, ftable, vtable[self.variable_name] @@ -43,34 +55,81 @@ class ExpABinop(Exp): self.exp1 = exp1 self.exp2 = exp2 + def __repr__(self) -> str: + return f"exp_a_binop({self.op}, {self.exp1}, {self.exp2})" + def eval(self, vtable, ftable): + vtable, ftable, r1 = self.exp1.eval(vtable, ftable) + if isinstance(r1,str): + if r1.isdigit(): + r1 = int(r1) + else: + r1 = float(r1) + vtable, ftable, r2 = self.exp2.eval(vtable, ftable) + if isinstance(r2,str): + if r2.isdigit(): + r2 = int(r2) + else: + r2 = float(r2) if self.op == "+": - vtable, ftable, r1 = self.exp1.eval(vtable, ftable) - vtable, ftable, r2 = self.exp2.eval(vtable, ftable) return vtable, ftable, r1+r2 elif self.op == "-": - vtable, ftable, r1 = self.exp1.eval(vtable, ftable) - vtable, ftable, r2 = self.exp2.eval(vtable, ftable) return vtable, ftable, r1-r2 elif self.op == "*": - vtable, ftable, r1 = self.exp1.eval(vtable, ftable) - vtable, ftable, r2 = self.exp2.eval(vtable, ftable) return vtable, ftable, r1*r2 elif self.op == "/": - vtable, ftable, r1 = self.exp1.eval(vtable, ftable) - vtable, ftable, r2 = self.exp2.eval(vtable, ftable) return vtable, ftable, r1/r2 elif self.op == "=": - vtable, ftable, r1 = self.exp1.eval(vtable, ftable) - vtable, ftable, r2 = self.exp2.eval(vtable, ftable) return vtable, ftable, r1 == r2 + elif self.op == ">": + return vtable, ftable, r1 > r2 + elif self.op == "<": + return vtable, ftable, r1 < r2 else: - raise Exception(f"Binop {self.op} not implemented") + print(f"E007: Unknown binop {self.op}") + exit() + +class ExpList(Exp): + def __init__(self, expressions: list[Exp]): + self.list = expressions + + def __repr__(self) -> str: + return f"exp_list([{rep_join(self.list)}])" + + def eval(self, vtable, ftable): + results = [] + for element in self.list: + vtable, ftable, result = element.eval(vtable, ftable) + results.append(result) + + return vtable, ftable, results + +class ExpIndex(Exp): + def __init__(self, items: ExpList, index: Exp): + self.list = items + self.index = index + + def __repr__(self) -> str: + return f"exp_index({self.list}, {self.index})" + + def eval(self, vtable, ftable): + vtable, ftable, elements = self.list.eval(vtable, ftable) + vtable, ftable, index = self.index.eval(vtable, ftable) + + if len(elements) > index: + result = elements[index] + else: + result = None + + return vtable, ftable, result class ExpArg(Exp): def __init__(self, arg: int): self.arg = arg + def __repr__(self) -> str: + return f"exp_arg({self.arg})" + def eval(self, vtable, ftable): n = vtable["#ARGS"] - self.arg @@ -80,11 +139,17 @@ class Command(BaseBox): def eval(self, vtable, ftable): return vtable, ftable, None + def __repr__(self) -> str: + return f"command()" + class Builtin(Command): def __init__(self, builtin: str, args: list[Exp]): self.builtin = builtin self.args = args + def __repr__(self) -> str: + return f"builtin({self.builtin}, {self.args})" + def eval(self, vtable, ftable): if self.builtin == "print": prints = [] @@ -94,14 +159,41 @@ class Builtin(Command): print(" ".join(prints)) - return vtable, ftable, None + return vtable, ftable, " ".join(prints) + elif self.builtin == "input": + if not self.args == []: + prints = [] + for arg in self.args: + vtable, ftable, result = arg.eval(vtable, ftable) + prints.append(str(result)) + + print(" ".join(prints), end="") + else: + print("> ", end="") + + result = input() + return vtable, ftable, result + elif self.builtin == "random": + if not len(self.args) == 2: + print(f"E006: Wrong number of arguments for builtin '{self.builtin}' ({len(self.args)})") + exit() + + vtable, ftable, r1 = self.args[0].eval(vtable, ftable) + vtable, ftable, r2 = self.args[1].eval(vtable, ftable) + + r = random.randint(r1, r2) + + return vtable, ftable, r else: - raise Exception(f"Unknown builtin {self.builtin}") + raise Exception(f"E005: Unknown builtin {self.builtin}") class Do(BaseBox): def __init__(self, command: Command): self.command = command + def __repr__(self) -> str: + return f"do({self.command})" + def eval(self, vtable, ftable): return self.command.eval(vtable, ftable) @@ -109,17 +201,23 @@ class Statement(BaseBox): def eval(self, vtable, ftable): return vtable, ftable, None + def __repr__(self) -> str: + return f"statement()" + class StatementSet(Statement): def __init__(self, expression: Exp, variable: str): self.expression = expression self.variable_name = variable + def __repr__(self) -> str: + return f"set({self.expression}, {self.variable_name})" + def eval(self, vtable, ftable): vtable, ftable, result = self.expression.eval( vtable, ftable ) vtable[self.variable_name] = result - return vtable, ftable, None + return vtable, ftable, result class StatementDefine(Statement): def __init__(self, function_name : str, parameters: int, statement: Statement): @@ -127,14 +225,20 @@ class StatementDefine(Statement): self.statement = statement self.parameters = parameters + def __repr__(self) -> str: + return f"define({self.function_name}, {self.statement}, {self.parameters})" + def eval(self, vtable, ftable): ftable[self.function_name] = (self.parameters, self.statement) - return vtable, ftable, None + return vtable, ftable, (self.parameters, self.statement) class StatementReturn(Statement): def __init__(self, expression: Exp): self.value = expression + def __repr__(self) -> str: + return f"return({self.value})" + def eval(self, vtable, ftable): vtable, ftable, result = self.value.eval(vtable, ftable) vtable["#return"] = result @@ -144,6 +248,9 @@ class Scope(Statement): def __init__(self, statements: list[Statement]): self.statements = statements + def __repr__(self) -> str: + return f"scope([{rep_join(self.statements)}])" + def eval(self, vtable, ftable): result = None for statement in self.statements: @@ -160,6 +267,9 @@ class Call(Statement): self.function_name = function_name self.arguments = arguments + def __repr__(self) -> str: + return f"call({self.function_name}, {self.arguments})" + def eval(self, vtable, ftable): assert len(self.arguments) == ftable[self.function_name][0] @@ -189,29 +299,61 @@ class StatementIf(Statement): self.statement = statement self.condition = condition + def __repr__(self) -> str: + return f"if({self.statement}, {self.condition})" + def eval(self, vtable, ftable): vtable, ftable, result = self.condition.eval(vtable, ftable) if result: return self.statement.eval(vtable, ftable) else: - return vtable, ftable, None + return vtable, ftable, result + +class StatementUntil(Statement): + def __init__(self, statement: Statement, condition): + self.statement = statement + self.condition = condition + + def __repr__(self) -> str: + return f"until({self.statement}, {self.condition})" + + def eval(self, vtable, ftable): + while True: + vtable, ftable, result = self.condition.eval(vtable, ftable) + if not result: + vtable, ftable, _ = self.statement.eval(vtable, ftable) + if "#return" in vtable: + result = vtable["#return"] + del vtable["#return"] + return vtable, ftable, result + else: + return vtable, ftable, result class Maybe(BaseBox): def __init__(self, statement : Statement): self.statement = statement + def __repr__(self) -> str: + return f"maybe({self.statement})" + def eval(self, vtable, ftable): if random.randint(0,1) == 1: return self.statement.eval(vtable,ftable) else: - return vtable, ftable, None + return vtable, ftable, False class Program(BaseBox): def __init__(self, statements: list[Statement]) -> None: self.statements = statements + random.seed(str(self)) + r = random.randint(1,20) + if r == 1: + print("E004: Random compiler error") + exit() + random.seed() def __repr__(self) -> str: - statements_string = f"statements([{rep_join(self.statements)}])" + statements_string = f"program([{rep_join(self.statements)}])" return statements_string def eval(self, *_): diff --git a/plthy_impl/lexer.py b/plthy_impl/lexer.py index e68666e..f2d2a98 100644 --- a/plthy_impl/lexer.py +++ b/plthy_impl/lexer.py @@ -9,7 +9,7 @@ KEYWORD_TOKENS = [("KEYWORD_"+i.upper(), i) for i in [ "maybe", "do", "if", - "because", +# "because", "until", "define", "as", @@ -19,18 +19,21 @@ KEYWORD_TOKENS = [("KEYWORD_"+i.upper(), i) for i in [ ]] BUILTIN_TOKENS = [("BUILTIN", i) for i in [ - "print" + "print", + "input", + "random" ]] DATA_TOKENS = [ ("DATA_STRING", r"\'.*?\'"), - ("DATA_NUMERAL", r"\d+(\.\d+)?") + ("DATA_INT", r"\d+"), + ("DATA_FLOAT", r"\d+(\.\d+)") ] SYMBOL_TOKENS = [ ("SYMBOL_SET", r"\-\>"), - ("SYMBOL_LPARENS", r"\("), - ("SYMBOL_RPARENS", r"\)"), +# ("SYMBOL_LPARENS", r"\("), +# ("SYMBOL_RPARENS", r"\)"), ("SYMBOL_LBRACKET", r"\["), ("SYMBOL_RBRACKET", r"\]"), ("SYMBOL_LCURL", r"\{"), @@ -39,8 +42,8 @@ SYMBOL_TOKENS = [ ("SYMBOL_MINUS", r"\-"), ("SYMBOL_TIMES", r"\*"), ("SYMBOL_DIVIDE", r"\/"), - ("SYMBOL_COMMA", r"\,"), - ("SYMBOL_COLON", r"\:"), +# ("SYMBOL_COMMA", r"\,"), +# ("SYMBOL_COLON", r"\:"), ("SYMBOL_SEMICOLON", r"\;"), ("SYMBOL_PIPE", r"\|"), ("SYMBOL_QUOTE", r"\""), diff --git a/plthy_impl/parser.py b/plthy_impl/parser.py index 908c6db..9674cd2 100644 --- a/plthy_impl/parser.py +++ b/plthy_impl/parser.py @@ -9,11 +9,11 @@ class Parser(): [i[0] for i in ALL_TOKENS], precedence=[ ('left', ["KEYWORD_MAYBE", "KEYWORD_RETURN"]), - ('left', ["KEYWORD_IF", "KEYWORD_DEFINE", "KEYWORD_AS"]), + ('left', ["KEYWORD_IF", "KEYWORD_UNTIL", "KEYWORD_DEFINE", "KEYWORD_AS"]), ('left', ["KEYWORD_DO", "BUILTIN"]), ('left', ["SYMBOL_EQUALS", "SYMBOL_SET"]), ('left', ["SYMBOL_PLUS", "SYMBOL_MINUS"]), - ('left', ["SYMBOL_TIMES", "SYMBOL_DIVIDE"]) + ('left', ["SYMBOL_TIMES", "SYMBOL_DIVIDE", "SYMBOL_LT","SYMBOL_GT"]) ] ) @@ -49,7 +49,11 @@ class Parser(): def statement_if(tokens): return ast_nodes.StatementIf(tokens[0], tokens[2]) - @self.pg.production('statement : KEYWORD_DEFINE ID SYMBOL_LT DATA_NUMERAL SYMBOL_GT KEYWORD_AS statement', precedence="KEYWORD_DEFINE") + @self.pg.production('statement : KEYWORD_UNTIL expression statement') + def statement_until(tokens): + return ast_nodes.StatementUntil(tokens[2],tokens[1]) + + @self.pg.production('statement : KEYWORD_DEFINE ID SYMBOL_LT DATA_INT SYMBOL_GT KEYWORD_AS statement', precedence="KEYWORD_DEFINE") def statement_define(tokens): return ast_nodes.StatementDefine(tokens[1].value, int(tokens[3].value), tokens[6]) @@ -80,9 +84,13 @@ class Parser(): return [tokens[0]] + tokens[2] ## expression ## - @self.pg.production('expression : DATA_NUMERAL') - def exp_numeral(tokens): - return ast_nodes.ExpNumeral(float(tokens[0].value)) + @self.pg.production('expression : DATA_INT') + def exp_int(tokens): + return ast_nodes.ExpInt(int(tokens[0].value)) + + @self.pg.production('expression : DATA_FLOAT') + def exp_int(tokens): + return ast_nodes.ExpInt(float(tokens[0].value)) @self.pg.production('expression : DATA_STRING') def exp_string(tokens): @@ -101,6 +109,8 @@ class Parser(): @self.pg.production('expression : expression SYMBOL_TIMES expression') @self.pg.production('expression : expression SYMBOL_DIVIDE expression') @self.pg.production('expression : expression SYMBOL_EQUALS expression') + @self.pg.production('expression : expression SYMBOL_LT expression') + @self.pg.production('expression : expression SYMBOL_GT expression') def exp_a_binop(tokens): return ast_nodes.ExpABinop(tokens[1].value,tokens[0],tokens[2]) @@ -108,10 +118,24 @@ class Parser(): def exp_arg(tokens): return ast_nodes.ExpArg(int(tokens[1].value[1:])) + @self.pg.production('expression : SYMBOL_LCURL expressions SYMBOL_RCURL') + def exp_list(tokens): + return ast_nodes.ExpList(tokens[1]) + + @self.pg.production('expression : expression SYMBOL_LCURL expression SYMBOL_RCURL') + def exp_index(tokens): + return ast_nodes.ExpIndex(tokens[0],tokens[2]) + ## Error Handling ## @self.pg.error def error_handle(token): - raise Exception(token.name, token.value, token.source_pos) + if token.source_pos is None: + print("E002: No valediction") + elif token.source_pos.lineno == 1 and token.source_pos.colno == 1: + print("E001: No greeting") + else: + print(f"E003: Unexpected token '{token.value}' ({token.name}) at line {token.source_pos.lineno}, column {token.source_pos.colno}.") + exit() ## Finish ## parser = self.pg.build() diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..2d04c0f --- /dev/null +++ b/test.sh @@ -0,0 +1,28 @@ +#! /usr/bin/bash + +for f in ./tests/*.plthy; do + filename=$(basename $f .plthy) + python ./plthy -i "tests/$filename.plthy" > "tests/$filename.output" + + printf '%-20s' "${filename/_/" "} " + + if test -f "tests/$filename.expected1"; then + match_found=0 + for g in ./tests/$filename.expected*; do + if cmp -s "$g" "tests/$filename.output"; then + echo "✓" + match_found=1 + break + fi + done + if [ $match_found -eq 0 ]; then + echo "X" + fi + else + if cmp -s "tests/$filename.expected" "tests/$filename.output"; then + echo "✓" + else + echo "X" + fi + fi +done diff --git a/tests/01_none.expected b/tests/01_none.expected new file mode 100644 index 0000000..e69de29 diff --git a/tests/none.plthy b/tests/01_none.plthy similarity index 100% rename from tests/none.plthy rename to tests/01_none.plthy diff --git a/tests/02_variable.expected b/tests/02_variable.expected new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/tests/02_variable.expected @@ -0,0 +1 @@ +2 diff --git a/tests/variable.plthy b/tests/02_variable.plthy similarity index 100% rename from tests/variable.plthy rename to tests/02_variable.plthy diff --git a/tests/03_math.expected b/tests/03_math.expected new file mode 100644 index 0000000..017ab29 --- /dev/null +++ b/tests/03_math.expected @@ -0,0 +1 @@ +4 2.0 2 diff --git a/tests/math.plthy b/tests/03_math.plthy similarity index 100% rename from tests/math.plthy rename to tests/03_math.plthy diff --git a/tests/04_scope.expected b/tests/04_scope.expected new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/tests/04_scope.expected @@ -0,0 +1 @@ +5 diff --git a/tests/scope.plthy b/tests/04_scope.plthy similarity index 100% rename from tests/scope.plthy rename to tests/04_scope.plthy diff --git a/tests/05_maybe.expected1 b/tests/05_maybe.expected1 new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/05_maybe.expected1 @@ -0,0 +1 @@ +1 diff --git a/tests/05_maybe.expected2 b/tests/05_maybe.expected2 new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/tests/05_maybe.expected2 @@ -0,0 +1 @@ +2 diff --git a/tests/maybe.plthy b/tests/05_maybe.plthy similarity index 100% rename from tests/maybe.plthy rename to tests/05_maybe.plthy diff --git a/tests/06_if.expected b/tests/06_if.expected new file mode 100644 index 0000000..6178079 --- /dev/null +++ b/tests/06_if.expected @@ -0,0 +1 @@ +b diff --git a/tests/if.plthy b/tests/06_if.plthy similarity index 100% rename from tests/if.plthy rename to tests/06_if.plthy diff --git a/tests/07_function.expected b/tests/07_function.expected new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/tests/07_function.expected @@ -0,0 +1 @@ +5 diff --git a/tests/function.plthy b/tests/07_function.plthy similarity index 100% rename from tests/function.plthy rename to tests/07_function.plthy diff --git a/tests/08_precedence.expected b/tests/08_precedence.expected new file mode 100644 index 0000000..b7dfd93 --- /dev/null +++ b/tests/08_precedence.expected @@ -0,0 +1,3 @@ +7 +5 +5 6 diff --git a/tests/precedence.plthy b/tests/08_precedence.plthy similarity index 66% rename from tests/precedence.plthy rename to tests/08_precedence.plthy index 34c6ade..203cca0 100644 --- a/tests/precedence.plthy +++ b/tests/08_precedence.plthy @@ -3,4 +3,6 @@ $ 1 + 2 * 3 -> x| do print| $ 5 -> y if variable x = 7| do print| +$$5 -> z + 1 -> a| +do print| goodbye| \ No newline at end of file diff --git a/tests/09_fib.expected b/tests/09_fib.expected new file mode 100644 index 0000000..ca8664f --- /dev/null +++ b/tests/09_fib.expected @@ -0,0 +1,5 @@ +1 +1 +2 +8 +55 diff --git a/tests/fib.plthy b/tests/09_fib.plthy similarity index 100% rename from tests/fib.plthy rename to tests/09_fib.plthy diff --git a/tests/10_E001.expected b/tests/10_E001.expected new file mode 100644 index 0000000..8c81fec --- /dev/null +++ b/tests/10_E001.expected @@ -0,0 +1 @@ +E001: No greeting diff --git a/tests/10_E001.plthy b/tests/10_E001.plthy new file mode 100644 index 0000000..15bcb54 --- /dev/null +++ b/tests/10_E001.plthy @@ -0,0 +1,2 @@ +$2 -> x| +goodbye| \ No newline at end of file diff --git a/tests/11_E002.expected b/tests/11_E002.expected new file mode 100644 index 0000000..a9cf250 --- /dev/null +++ b/tests/11_E002.expected @@ -0,0 +1 @@ +E002: No valediction diff --git a/tests/11_E002.plthy b/tests/11_E002.plthy new file mode 100644 index 0000000..7a71af5 --- /dev/null +++ b/tests/11_E002.plthy @@ -0,0 +1,2 @@ +hello| +$2 -> x| \ No newline at end of file diff --git a/tests/12_list.expected b/tests/12_list.expected new file mode 100644 index 0000000..58a437d --- /dev/null +++ b/tests/12_list.expected @@ -0,0 +1,3 @@ +[1, 2, 3] +3 +2 diff --git a/tests/12_list.plthy b/tests/12_list.plthy new file mode 100644 index 0000000..e491c73 --- /dev/null +++ b/tests/12_list.plthy @@ -0,0 +1,6 @@ +hello| +${1;2;3;} -> x| +do print| +${1;1+1;do print<3;>;} -> y| +do print| +goodbye| \ No newline at end of file