From 5d8c31fb071c162fec2718052a88d4631e2251c4 Mon Sep 17 00:00:00 2001 From: nocturn9x Date: Fri, 26 Feb 2021 12:27:10 +0100 Subject: [PATCH 1/5] Fixed identity operator bug and added isnot for consistency. Changed behavior for gt/lt comparisons to account for more complex expressions --- build.py | 2 +- src/compiler.nim | 11 +++-- src/lexer.nim | 2 +- src/meta/opcode.nim | 4 +- src/meta/token.nim | 3 +- src/types/function.nim | 2 +- src/types/methods.nim | 4 +- src/types/numbers.nim | 104 ++++++++++++++++++++++++---------------- src/vm.nim | 51 ++++++++++++++++++-- tests/japl/booleans.jpl | 8 ++-- tests/japl/is.jpl | 1 - 11 files changed, 132 insertions(+), 60 deletions(-) diff --git a/build.py b/build.py index c8688b6..dbcacdf 100755 --- a/build.py +++ b/build.py @@ -196,7 +196,7 @@ def build(path: str, flags: Optional[Dict[str, str]] = {}, options: Optional[Dic logging.debug("Running tests") start = time() # TODO: Find a better way of running the test suite - process = run_command(f"{tests_path}", mode="run", shell=True, stderr=PIPE) + process = run_command(f"{tests_path} {'--stdout' if verbose else ''}", mode="run", shell=True, stderr=PIPE) if status != 0: logging.error(f"Command '{command}' exited with non-0 exit code {status}, output below:\n{stderr.decode()}") else: diff --git a/src/compiler.nim b/src/compiler.nim index 5e287ea..20727fc 100644 --- a/src/compiler.nim +++ b/src/compiler.nim @@ -312,11 +312,11 @@ proc binary(self: Compiler, canAssign: bool) = of TokenType.GT: self.emitByte(OpCode.Greater) of TokenType.GE: - self.emitBytes(OpCode.Less, OpCode.Not) + self.emitByte(OpCode.GreaterOrEqual) of TokenType.LT: self.emitByte(OpCode.Less) of TokenType.LE: - self.emitBytes(OpCode.Greater, OpCode.Not) + self.emitByte(OpCode.LessOrEqual) of TokenType.CARET: self.emitByte(OpCode.Xor) of TokenType.SHL: @@ -329,6 +329,8 @@ proc binary(self: Compiler, canAssign: bool) = self.emitByte(OpCode.Band) of TokenType.IS: self.emitByte(OpCode.Is) + of TokenType.ISNOT: + self.emitBytes(OpCode.Is, Opcode.Not) of TokenType.AS: self.emitByte(OpCode.As) else: @@ -991,7 +993,7 @@ proc statement(self: Compiler) = ## Parses statements if self.parser.match(TokenType.FOR): self.forStatement() - elif self.parser.match(IF): + elif self.parser.match(TokenType.IF): self.ifStatement() elif self.parser.match(TokenType.WHILE): self.whileStatement() @@ -1102,7 +1104,8 @@ var rules: array[TokenType, ParseRule] = [ makeRule(unary, nil, Precedence.None), # TILDE makeRule(nil, binary, Precedence.Is), # IS makeRule(nil, binary, Precedence.As), # AS - makeRule(parseLambda, nil, Precedence.None) # LAMBDA + makeRule(parseLambda, nil, Precedence.None), # LAMBDA + makeRule(nil, binary, Precedence.Is), # ISNOT ] diff --git a/src/lexer.nim b/src/lexer.nim index 163d33b..e59c655 100644 --- a/src/lexer.nim +++ b/src/lexer.nim @@ -58,7 +58,7 @@ const RESERVED = to_table({ "continue": TokenType.CONTINUE, "inf": TokenType.INF, "nan": TokenType.NAN, "is": TokenType.IS, "not": TokenType.NEG, "as": TokenType.AS, - "lambda": TokenType.LAMBDA}) + "lambda": TokenType.LAMBDA, "isnot": TokenType.ISNOT}) type Lexer* = ref object source*: string diff --git a/src/meta/opcode.nim b/src/meta/opcode.nim index da3d421..ac53388 100644 --- a/src/meta/opcode.nim +++ b/src/meta/opcode.nim @@ -44,6 +44,8 @@ type Greater, Less, Equal, + GreaterOrEqual, + LessOrEqual, Not, GetItem, Slice, @@ -81,7 +83,7 @@ const simpleInstructions* = {OpCode.Return, OpCode.Add, OpCode.Multiply, OpCode.Xor, OpCode.Not, OpCode.Equal, OpCode.Greater, OpCode.Less, OpCode.GetItem, OpCode.Slice, OpCode.Pop, OpCode.Negate, - OpCode.Is, OpCode.As} + OpCode.Is, OpCode.As, GreaterOrEqual, LessOrEqual} const constantInstructions* = {OpCode.Constant, OpCode.DefineGlobal, OpCode.GetGlobal, OpCode.SetGlobal, OpCode.DeleteGlobal} diff --git a/src/meta/token.nim b/src/meta/token.nim index 1a291a7..4c206ee 100644 --- a/src/meta/token.nim +++ b/src/meta/token.nim @@ -29,7 +29,8 @@ type WHILE, DEL, BREAK, EOF, COLON, CONTINUE, CARET, SHL, SHR, NAN, INF, BAND, - BOR, TILDE, IS, AS, LAMBDA + BOR, TILDE, IS, AS, LAMBDA, + ISNOT Token* = object kind*: TokenType lexeme*: string diff --git a/src/types/function.nim b/src/types/function.nim index 8375a8e..976fc4a 100644 --- a/src/types/function.nim +++ b/src/types/function.nim @@ -31,7 +31,7 @@ proc newFunction*(name: string = "", chunk: Chunk, arity: int = 0): ptr Function ## anonymous code object # TODO: Add support for optional parameters result = allocateObj(Function, ObjectType.Function) - if name.len > 1: + if name.len >= 1: result.name = name.asStr() else: result.name = nil diff --git a/src/types/methods.nim b/src/types/methods.nim index 606bd8e..bb7f0de 100644 --- a/src/types/methods.nim +++ b/src/types/methods.nim @@ -391,7 +391,7 @@ proc binaryNot*(self: ptr Obj): returnType = raise newException(NotImplementedError, "") -proc lt*(self: ptr Obj, other: ptr Obj): bool = +proc lt*(self: ptr Obj, other: ptr Obj): tuple[result: bool, obj: ptr Obj] = ## Returns the result of self < other or ## raises an error if the operation ## is unsupported @@ -406,7 +406,7 @@ proc lt*(self: ptr Obj, other: ptr Obj): bool = raise newException(NotImplementedError, "") -proc gt*(self: ptr Obj, other: ptr Obj): bool = +proc gt*(self: ptr Obj, other: ptr Obj): tuple[result: bool, obj: ptr Obj] = ## Returns the result of self > other or ## raises an error if the operation ## is unsupported diff --git a/src/types/numbers.nim b/src/types/numbers.nim index f242c06..7a7a5c5 100644 --- a/src/types/numbers.nim +++ b/src/types/numbers.nim @@ -133,50 +133,50 @@ proc eq*(self, other: ptr Infinity): bool = result = self.isNegative == other.isNegative -proc lt*(self: ptr Infinity, other: ptr Obj): bool = +proc lt*(self: ptr Infinity, other: ptr Obj): tuple[result: bool, obj: ptr Obj] = case other.kind: of ObjectType.Integer: let other = cast[ptr Integer](other) - if self.isNegative and other.intValue > 0: - result = true + if self.isNegative: + result = (result: true, obj: other) else: - result = false + result = (result: false, obj: nil) of ObjectType.Float: let other = cast[ptr Float](other) - if self.isNegative and other.floatValue > 0.0: - result = true + if self.isNegative: + result = (result: true, obj: other) else: - result = false + result = (result: false, obj: nil) of ObjectType.Infinity: let other = cast[ptr Infinity](other) if other.isNegative and not self.isNegative: - result = false + result = (result: true, obj: other) else: - result = false + result = (result: false, obj: nil) else: raise newException(NotImplementedError, "") -proc gt*(self: ptr Infinity, other: ptr Obj): bool = +proc gt*(self: ptr Infinity, other: ptr Obj): tuple[result: bool, obj: ptr Obj] = case other.kind: of ObjectType.Integer: let other = cast[ptr Integer](other) - if self.isNegative and other.intValue > 0: - result = false + if self.isNegative: + result = (result: false, obj: nil) else: - result = true + result = (result: true, obj: other) of ObjectType.Float: let other = cast[ptr Float](other) - if self.isNegative and other.floatValue > 0.0: - result = false + if self.isNegative: + result = (result: false, obj: nil) else: - result = true + result = (result: true, obj: other) of ObjectType.Infinity: let other = cast[ptr Infinity](other) if other.isNegative and not self.isNegative: - result = true + result = (result: false, obj: nil) else: - result = false + result = (result: true, obj: other) else: raise newException(NotImplementedError, "") @@ -216,7 +216,7 @@ proc stringify*(self: ptr Float): string = proc isFalsey*(self: ptr Float): bool = - result = self.floatValue == 0.0 + result = false proc hash*(self: ptr Float): uint64 = @@ -243,7 +243,7 @@ proc stringify*(self: ptr Integer): string = proc isFalsey*(self: ptr Integer): bool = - result = self.intValue == 0 + result = false proc eq*(self, other: ptr Integer): bool = @@ -259,66 +259,90 @@ proc hash*(self: ptr Integer): uint64 = result = uint64 self.intValue -proc lt*(self: ptr Integer, other: ptr Obj): bool = +proc lt*(self: ptr Integer, other: ptr Obj): tuple[result: bool, obj: ptr Obj] = case other.kind: of ObjectType.Integer: - result = self.intValue < cast[ptr Integer](other).intValue + if self.intValue < cast[ptr Integer](other).intValue: + result = (result: true, obj: other) + else: + result = (result: false, obj: nil) of ObjectType.Float: - result = (float self.intValue) < cast[ptr Float](other).floatValue + if (float self.intValue) < cast[ptr Float](other).floatValue: + result = (result: true, obj: other) + else: + result = (result: false, obj: nil) of ObjectType.Infinity: let other = cast[ptr Infinity](other) if other.isNegative: - result = false + result = (result: true, obj: other) else: - result = true + result = (result: false, obj: nil) else: raise newException(NotImplementedError, "") -proc lt*(self: ptr Float, other: ptr Obj): bool = +proc lt*(self: ptr Float, other: ptr Obj): tuple[result: bool, obj: ptr Obj] = case other.kind: of ObjectType.Integer: - result = self.floatValue < (float cast[ptr Integer](other).intValue) + if self.floatValue < (float cast[ptr Integer](other).intValue): + result = (result: true, obj: other) + else: + result = (result: false, obj: nil) of ObjectType.Float: - result = self.floatValue < cast[ptr Float](other).floatValue + if self.floatValue < cast[ptr Float](other).floatValue: + result = (result: true, obj: other) + else: + result = (result: false, obj: nil) of ObjectType.Infinity: let other = cast[ptr Infinity](other) if other.isNegative: - result = false + result = (result: true, obj: other) else: - result = true + result = (result: false, obj: nil) else: raise newException(NotImplementedError, "") -proc gt*(self: ptr Integer, other: ptr Obj): bool = +proc gt*(self: ptr Integer, other: ptr Obj): tuple[result: bool, obj: ptr Obj] = case other.kind: of ObjectType.Integer: - result = self.intValue > cast[ptr Integer](other).intValue + if self.intValue > cast[ptr Integer](other).intValue: + result = (result: true, obj: other) + else: + result = (result: false, obj: nil) of ObjectType.Float: - result = (float self.intValue) > cast[ptr Float](other).floatValue + if (float self.intValue) > cast[ptr Float](other).floatValue: + result = (result: true, obj: other) + else: + result = (result: false, obj: nil) of ObjectType.Infinity: let other = cast[ptr Infinity](other) if other.isNegative: - result = true + result = (result: true, obj: other) else: - result = false + result = (result: false, obj: nil) else: raise newException(NotImplementedError, "") -proc gt*(self: ptr Float, other: ptr Obj): bool = +proc gt*(self: ptr Float, other: ptr Obj): tuple[result: bool, obj: ptr Obj] = case other.kind: of ObjectType.Integer: - result = self.floatValue > (float cast[ptr Integer](other).intValue) + if self.floatValue > (float cast[ptr Integer](other).intValue): + result = (result: true, obj: other) + else: + result = (result: false, obj: nil) of ObjectType.Float: - result = self.floatValue > cast[ptr Float](other).floatValue + if self.floatValue > cast[ptr Float](other).floatValue: + result = (result: true, obj: other) + else: + result = (result: false, obj: nil) of ObjectType.Infinity: let other = cast[ptr Infinity](other) if other.isNegative: - result = true + result = (result: true, obj: other) else: - result = false + result = (result: false, obj: nil) else: raise newException(NotImplementedError, "") diff --git a/src/vm.nim b/src/vm.nim index f440d91..64c17a8 100644 --- a/src/vm.nim +++ b/src/vm.nim @@ -505,8 +505,13 @@ proc run(self: VM): InterpretResult = # Binary less (<) var right = self.pop() var left = self.pop() + var comp: tuple[result: bool, obj: ptr Obj] try: - self.push(self.getBoolean(left.lt(right))) + comp = left.lt(right) + if system.`==`(comp.obj, nil): + self.push(self.getBoolean(comp.result)) + else: + self.push(comp.obj) except NotImplementedError: self.error(newTypeError(&"unsupported binary operator '<' for objects of type '{left.typeName()}' and '{right.typeName()}'")) return RuntimeError @@ -514,18 +519,55 @@ proc run(self: VM): InterpretResult = # Binary greater (>) var right = self.pop() var left = self.pop() + var comp: tuple[result: bool, obj: ptr Obj] try: - self.push(self.getBoolean(left.gt(right))) + comp = left.gt(right) + if system.`==`(comp.obj, nil): + self.push(self.getBoolean(comp.result)) + else: + self.push(comp.obj) + except NotImplementedError: + self.error(newTypeError(&"unsupported binary operator '>' for objects of type '{left.typeName()}' and '{right.typeName()}'")) + return RuntimeError + of OpCode.LessOrEqual: + var right = self.pop() + var left = self.pop() + var comp: tuple[result: bool, obj: ptr Obj] + try: + comp = left.lt(right) + if not comp.result and left == right: + comp.result = true + if system.`==`(comp.obj, nil): + self.push(self.getBoolean(comp.result)) + else: + self.push(comp.obj) + except NotImplementedError: + self.error(newTypeError(&"unsupported binary operator '<' for objects of type '{left.typeName()}' and '{right.typeName()}'")) + return RuntimeError + of OpCode.GreaterOrEqual: + var right = self.pop() + var left = self.pop() + var comp: tuple[result: bool, obj: ptr Obj] + try: + comp = left.gt(right) + if not comp.result and left == right: + comp.result = true + if system.`==`(comp.obj, nil): + self.push(self.getBoolean(comp.result)) + else: + self.push(comp.obj) except NotImplementedError: self.error(newTypeError(&"unsupported binary operator '>' for objects of type '{left.typeName()}' and '{right.typeName()}'")) return RuntimeError of OpCode.Is: # Implements object identity (i.e. same pointer) # This is implemented internally for obvious - # reasons and works on any pair of objects + # reasons and works on any pair of objects, which + # is why we call nim's system.== operator and NOT + # our custom one var right = self.pop() var left = self.pop() - self.push(self.getBoolean(left == right)) + self.push(self.getBoolean(system.`==`(left, right))) of OpCode.As: # Implements type casting (TODO: Only allow classes) var right = self.pop() @@ -629,6 +671,7 @@ proc run(self: VM): InterpretResult = # Handles returning values from the callee to the caller # and sets up the stack to proceed with execution var retResult = self.pop() + # Pops the function's frame discard self.frames.pop() if self.frames.len() == 0: discard self.pop() diff --git a/tests/japl/booleans.jpl b/tests/japl/booleans.jpl index ac15abd..d62115b 100644 --- a/tests/japl/booleans.jpl +++ b/tests/japl/booleans.jpl @@ -9,17 +9,17 @@ print(false and 3 or 4);//stdout:4 print(true and 3 or 4);//stdout:3 print(true and 2);//stdout:2 print(false or 5);//stdout:5 -print(0 or 4);//stdout:4 -print(0 and true);//stdout:0 +print(nil or 4);//stdout:4 +print(0 or true);//stdout:0 print("" and true);//stdout:'' print("" or true);//stdout:true print(1 or 2 or 3 or 4);//stdout:1 print(1 and 2 and 3 and 4);//stdout:4 print(1 and 2 or 3 and 4);//stdout:2 print(1 and false or 3 and 4);//stdout:4 -print(not 0);//stdout:true +print(not false);//stdout:true print(not 1);//stdout:false print(not 1 and not 2);//stdout:false -print(not (1 and 0));//stdout:true +print(not (1 and false));//stdout:true [end] [end] diff --git a/tests/japl/is.jpl b/tests/japl/is.jpl index 1900ce3..92bc584 100644 --- a/tests/japl/is.jpl +++ b/tests/japl/is.jpl @@ -1,5 +1,4 @@ [Test: is] -[skip] [source:mixed] var x = 4; var y = x; From 67daca932fd64c3b5074eb65eddcdc5291cde62f Mon Sep 17 00:00:00 2001 From: Mattia Date: Fri, 26 Feb 2021 13:56:56 +0100 Subject: [PATCH 2/5] Create main.yml --- .github/workflows/main.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..865a5ed --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,26 @@ +# Automatically runs tests + +name: Run tests + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + workflow_dispatch: + +jobs: + tests: + runs-on: ubuntu-latest + steps: + - name: Setup Python + uses: actions/setup-python@v2.2.1 + with: + # We test using a reasonably modern Python version + python-version: 3.8.0 + architecture: x64 + - uses: japl-lang/japl@v2 + - name: Run production-mode tests + run: ./build.py --profile resources/profiles/production.json + - name: Run developmet tests + run: ./build.py --profile resources/profiles/production.json From de470a38438f4a9eed9bd611fb528b0f04b80494 Mon Sep 17 00:00:00 2001 From: nocturn9x Date: Fri, 26 Feb 2021 14:01:12 +0100 Subject: [PATCH 3/5] Test for github actions --- build.py | 63 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/build.py b/build.py index dbcacdf..8d35896 100755 --- a/build.py +++ b/build.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 - + # Copyright 2020 Mattia Giambirtone # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -148,7 +148,7 @@ def build(path: str, flags: Optional[Dict[str, str]] = {}, options: Optional[Dic listing = "\n- {} = {}" if not os.path.exists(path): logging.error(f"Input path '{path}' does not exist") - return + return False if os.path.isfile(config_path) and not override: logging.warning(f"A config file exists at '{config_path}', keeping it") else: @@ -159,7 +159,7 @@ def build(path: str, flags: Optional[Dict[str, str]] = {}, options: Optional[Dic build_config.write(CONFIG_TEMPLATE.format(**options)) except Exception as fatal: logging.error(f"A fatal unhandled exception occurred -> {type(fatal).__name__}: {fatal}") - return + return False else: logging.debug(f"Config file has been generated, compiling with options as follows: {''.join(listing.format(k, v) for k, v in options.items())}") logging.debug(f"Nim compiler options: {''.join(listing.format(k, v) for k, v in flags.items())}") @@ -186,22 +186,22 @@ def build(path: str, flags: Optional[Dict[str, str]] = {}, options: Optional[Dic _, stderr, status = run_command(command, stdout=DEVNULL, stderr=PIPE) if status != 0: logging.error(f"Command '{command}' exited with non-0 exit code {status}, output below:\n{stderr.decode()}") - else: - command = f"nim compile --opt:speed {tests_path}" - _, stderr, status = run_command(command, stdout=DEVNULL, stderr=PIPE) - if status != 0: - logging.error(f"Command '{command}' exited with non-0 exit code {status}, output below:\n{stderr.decode()}") - else: - logging.debug(f"Test suite compilation completed in {time() - start:.2f} seconds") - logging.debug("Running tests") - start = time() - # TODO: Find a better way of running the test suite - process = run_command(f"{tests_path} {'--stdout' if verbose else ''}", mode="run", shell=True, stderr=PIPE) - if status != 0: - logging.error(f"Command '{command}' exited with non-0 exit code {status}, output below:\n{stderr.decode()}") - else: - logging.debug(f"Test suite ran in {time() - start:.2f} seconds") - logging.info("Test suite completed!") + return False + command = f"nim compile --opt:speed {tests_path}" + _, stderr, status = run_command(command, stdout=DEVNULL, stderr=PIPE) + if status != 0: + logging.error(f"Command '{command}' exited with non-0 exit code {status}, output below:\n{stderr.decode()}") + return False + logging.debug(f"Test suite compilation completed in {time() - start:.2f} seconds") + logging.debug("Running tests") + start = time() + # TODO: Find a better way of running the test suite + process = run_command(f"{tests_path} {'--stdout' if verbose else ''}", mode="run", shell=True, stderr=PIPE) + if status != 0: + logging.error(f"Command '{command}' exited with non-0 exit code {status}, output below:\n{stderr.decode()}") + return False + logging.debug(f"Test suite ran in {time() - start:.2f} seconds") + logging.info("Test suite completed!") if args.install: if os.name == "nt": logging.warning("Sorry, but automatically installing JAPL is not yet supported on windows") @@ -220,14 +220,15 @@ def build(path: str, flags: Optional[Dict[str, str]] = {}, options: Optional[Dic logging.debug(f"Path '{path}' is not writable, attempting next entry in PATH") except Exception as fatal: logging.error(f"A fatal unhandled exception occurred -> {type(fatal).__name__}: {fatal}") - else: - logging.debug(f"JAPL installed at '{path}', setting executable permissions") - # TODO: Use external oschmod library once we support windows! - try: - os.chmod(install_path, os.stat(install_path).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) - except Exception as fatal: - logging.error(f"A fatal unhandled exception occurred -> {type(fatal).__name__}: {fatal}") - break + return False + logging.debug(f"JAPL installed at '{path}', setting executable permissions") + # TODO: Use external oschmod library once we support windows! + try: + os.chmod(install_path, os.stat(install_path).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) + except Exception as fatal: + logging.error(f"A fatal unhandled exception occurred -> {type(fatal).__name__}: {fatal}") + break + return True if __name__ == "__main__": @@ -310,14 +311,16 @@ if __name__ == "__main__": exit() else: logging.info(f"Using profile '{args.profile}'") - build(args.path, + if build(args.path, flags, options, args.override_config, args.skip_tests, args.install, args.ignore_binary, - args.verbose) - logging.debug("Build tool exited") + args.verbose): + logging.debug("Build tool exited successfully") + else: + except KeyboardInterrupt: logging.info("Interrupted by the user") From 75e02e13242ae45e6f54d990719a5aad3b78e4a8 Mon Sep 17 00:00:00 2001 From: Mattia Date: Fri, 26 Feb 2021 14:03:17 +0100 Subject: [PATCH 4/5] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 865a5ed..2706fab 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: # We test using a reasonably modern Python version python-version: 3.8.0 architecture: x64 - - uses: japl-lang/japl@v2 + - uses: actions/checkout@v2 - name: Run production-mode tests run: ./build.py --profile resources/profiles/production.json - name: Run developmet tests From 8d468e7bedd306e3ae268fb4811206d49b482d88 Mon Sep 17 00:00:00 2001 From: nocturn9x Date: Fri, 26 Feb 2021 14:04:38 +0100 Subject: [PATCH 5/5] Fixed build script (oof) --- build.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.py b/build.py index 8d35896..75019b5 100755 --- a/build.py +++ b/build.py @@ -321,6 +321,7 @@ if __name__ == "__main__": args.verbose): logging.debug("Build tool exited successfully") else: - + logging.debug("Build tool exited with error") + exit(1) except KeyboardInterrupt: logging.info("Interrupted by the user")