From 91dbad2f2004819b3ed9301d39221fb5d3987b0b Mon Sep 17 00:00:00 2001
From: pycsham <shampuiyanchloe@gmail.com>
Date: Sun, 16 Feb 2020 23:07:44 -0500
Subject: [PATCH] fixed integer range checking in Scanning

---
 ChloeTests/ErrorTest.py | 69 +++++++++++++++++++++++++++++++++++++++
 ChloeTests/Test.py      | 72 +++++++++++++++++++++++++++++++++++++++++
 Scanning.py             | 46 +++++++++++++++++---------
 3 files changed, 171 insertions(+), 16 deletions(-)
 create mode 100644 ChloeTests/ErrorTest.py
 create mode 100644 ChloeTests/Test.py

diff --git a/ChloeTests/ErrorTest.py b/ChloeTests/ErrorTest.py
new file mode 100644
index 0000000..aba22c8
--- /dev/null
+++ b/ChloeTests/ErrorTest.py
@@ -0,0 +1,69 @@
+import sys
+from os import listdir
+from os.path import isfile, join
+
+from Scanning import scan
+from Parsing import parse
+import Weeding
+
+
+def allFiles(testDir):
+     return [testDir + f for f in listdir(testDir) if isfile(join(testDir, f)) and f.startswith('Je')]
+
+def main():
+
+    # All files in the test directory
+    testDirectory = "./Tests/"
+    testFiles = allFiles(testDirectory)
+    # testFiles = ['./Tests/Je_1_IntRange_MinusTooBigInt.java']
+    print("**********************************************************")
+
+    for f in testFiles:
+        # print(f)
+
+        # Scanning
+        content = open(f, "r").read()
+        (tokens, errorString) = scan(content)
+        # Error in Scanning
+        if tokens is None:
+            # print("ERROR in Scanning: " + errorString)
+            # print("**********************************************************")
+            continue
+
+        # s = "All Tokens: "
+        # for token in tokens:
+        #     if (token.name and token.lex):
+        #         s += '(' + token.name + ',' + token.lex + '), '
+        # print(s)
+
+        # No weeds if everything is good (weeds = None)
+        weeds = Weeding.fileNameCheck(tokens, f)
+        if weeds:
+            # print(weeds)
+            continue
+
+
+
+        # Parsing
+        # print("Parsing starts")
+
+        try:
+            (steps, errorString) = parse(tokens)
+        except:
+            print("Exception in Parsing")
+        
+        # Error in Parsing
+        if steps is None:
+            # print("ERROR in Parsing: ", errorString)
+            # print("**********************************************************")
+            continue
+
+        print(f)
+        print("Succeeded")
+        # print("All Steps:")
+        # print(steps)
+
+        print("**********************************************************")
+
+main()
+
diff --git a/ChloeTests/Test.py b/ChloeTests/Test.py
new file mode 100644
index 0000000..02941d7
--- /dev/null
+++ b/ChloeTests/Test.py
@@ -0,0 +1,72 @@
+import sys
+from os import listdir
+from os.path import isfile, join
+
+from Scanning import scan
+from Parsing import parse
+import Weeding
+
+
+def allFiles(testDir):
+     return [testDir + f for f in listdir(testDir) if isfile(join(testDir, f)) and f.startswith('J1')]
+
+def main():
+
+    # All files in the test directory
+    testDirectory = "./Tests/"
+    testFiles = allFiles(testDirectory)
+    testFiles = ['./Tests/J1_IntRange_MinNegativeInt.java']
+    print("**********************************************************")
+
+    for f in testFiles:
+        # print(f)
+
+        # Scanning
+        content = open(f, "r").read()
+        (tokens, errorString) = scan(content)
+        # Error in Scanning
+        if tokens is None:
+            print(f)
+            print("ERROR in Scanning: " + errorString)
+            print("**********************************************************")
+            continue
+
+        s = "All Tokens: "
+        for token in tokens:
+            if (token.name and token.lex):
+                s += '(' + token.name + ',' + token.lex + '), '
+        print(s)
+
+        # No weeds if everything is good (weeds = None)
+        weeds = Weeding.fileNameCheck(tokens, f)
+        if weeds:
+            print(weeds)
+            continue
+
+
+
+        # Parsing
+        # print("Parsing starts")
+
+        try:
+            (steps, errorString) = parse(tokens)
+        except:
+            print("Exception in Parsing")
+        
+        # Error in Parsing
+        if steps is None:
+            # print(f)
+            # # print("ERROR IN PARSING")
+            # print("ERROR in Parsing: ", errorString)
+            # print("**********************************************************")
+            continue
+
+        # print(f)
+        # print("Succeeded")
+        # print("All Steps:")
+        # print(steps)
+
+        print("**********************************************************")
+
+main()
+
diff --git a/Scanning.py b/Scanning.py
index ab4ced5..5d86346 100644
--- a/Scanning.py
+++ b/Scanning.py
@@ -106,6 +106,7 @@ JoosDFATokens = set([
     # Literals and names (note: 'this' is considered as a keyword)
     'NUM',            # number (excludes 0)
     'ZERO',           # 0
+    'NEGATIVENUM',    # to do integer range checking, will be mapped to NUM after checking
     'LITERALBOOL',    # true or false
     'LITERALCHAR',    # character e.g. 'c', includes escape characters?
     'LITERALSTRING',  # string e.g. "hello", includes escape sequences
@@ -238,7 +239,7 @@ def JoosTransition(input, state):
         if (input == '\''):
             return 'LCHAR'
 
-    # Handling all operators that are not allowed in Joos (some cases are handled elsewhere)
+    # Handling all operators that are not allowed in Joos (some cases are handled elsewhere) and negative numbers
     elif state == 'ADD':
         if input == '+':
             return 'OPDISCARD'
@@ -248,6 +249,8 @@ def JoosTransition(input, state):
     elif state == 'SUB':
         if (input == '>'):
             return 'OPDISCARD'
+        if input.isdigit():
+            return 'NEGATIVENUM'
         if input == '-':
             return 'OPDISCARD'
         if input == '=':
@@ -293,6 +296,13 @@ def JoosTransition(input, state):
         if input == '.':
             return 'FLOAT' # not accepted
         return None
+    
+    elif state == 'NEGATIVENUM':
+        if input.isdigit():
+            return 'NEGATIVENUM'
+        if input == '.':
+            return 'FLOAT' # not accepted
+        return None
 
     # string literal
     elif (state == 'LSTRING'):
@@ -372,7 +382,7 @@ def JoosTransition(input, state):
         elif input == '=':
             return 'OPDISCARD'
         return None
-
+    
 
     # Comments
     elif(state == 'DIV'):
@@ -494,12 +504,9 @@ def scan(input):
                 if index < indexRange-1:
                     if tokens[index+1].name == 'NUM':
                         return (None, "wrong integer literal: starts with 0")
-            # Checking integer range (does not cover all edge cases)
-            # elif token.name == 'NUM' and index > 0 and tokens[index-1].name == 'SUB' and int(token.lex) > 2147483648:
-            #     return (None, "integer too small")
-            # elif token.name == 'NUM' and int(token.lex) > 2147483647 and (index is 0 or tokens[index-1].name is not 'SUB'):
-            #     return (None, "interger too large")
-
+            # Checking integer range 
+            elif token.name == 'NEGATIVENUM' and int(token.lex) < -2147483648:
+                return (None, "negative int too large")
 
             # dealing with keywords in Java but not in Joos
             elif token.name == 'ID' and token.lex in wrongJavaKeyWordDict:
@@ -536,13 +543,20 @@ def scan(input):
         idsToTokens(tokens)
 
         # remove whitespace, newline characters and comments
-        tokens = list(filter(lambda t: t.name not in ("WHITESPACE", "COMMENT", 'LCOMMENT', 'RCOMMENT', 'NEWLINE', 'NEWLINEC', 'LCOM2', 'LCOM3'), tokens))
+        tokens = list(filter(lambda t: t.name not in ("COMMENT", 'LCOMMENT', 'RCOMMENT', 'NEWLINE', 'NEWLINEC', 'LCOM2', 'LCOM3'), tokens))
 
         for index,token in enumerate(tokens):
-            # Checking integer range (does not cover all edge cases)
-            if token.name == 'NUM' and index > 0 and tokens[index-1].name == 'SUB' and int(token.lex) > 2147483648:
-                return (None, "integer too small")
-            elif token.name == 'NUM' and int(token.lex) > 2147483647 and (index is 0 or tokens[index-1].name is not 'SUB'):
-                return (None, "interger too large")
-
-    return (tokens, "success")
+            if token.name == 'NUM' and int(token.lex) > 2147483647 and (index is 0 or tokens[index-1].name is not 'SUB'):
+                return (None, "positive int too large")
+        
+        tokens = list(filter(lambda t: t.name is not 'WHITESPACE', tokens))
+        
+        tokensNew = []
+        for index, t in enumerate(tokens):
+            if t.name is 'NEGATIVENUM':
+                tokensNew.append(Token('SUB', '-'))
+                tokensNew.append(Token('NUM', t.lex[1:]))
+            else:
+                tokensNew.append(t)
+
+    return (tokensNew, "success")
-- 
GitLab