├── example ├── unhandled_exception.vg ├── failed_implore.vg ├── failed_swear.vg └── hello.vg ├── vigil └── README.md /example/unhandled_exception.vg: -------------------------------------------------------------------------------- 1 | # This shows what happens when a function throws an unhandled exception. 2 | 3 | def say_hello(who): 4 | """ 5 | Greets 'who'. 6 | """ 7 | 8 | print "Hi,", who 9 | raise Exception("ERROR!") # Oops. 10 | 11 | def innocent_fn(): 12 | say_hello('Bob') 13 | 14 | def main(): 15 | innocent_fn() 16 | -------------------------------------------------------------------------------- /example/failed_implore.vg: -------------------------------------------------------------------------------- 1 | # This shows what happens when a caller fails to keep its oath. 2 | import math 3 | 4 | def square_root(n): 5 | """ 6 | Calculates the square root of the given number, which must be non-negative. 7 | """ 8 | implore n >= 0 9 | 10 | return math.sqrt(abs(n)) 11 | 12 | def evil_fn(): 13 | square_root(-1) 14 | 15 | def main(): 16 | evil_fn() 17 | -------------------------------------------------------------------------------- /example/failed_swear.vg: -------------------------------------------------------------------------------- 1 | # This shows what happens when a function fails to keep its oath. 2 | 3 | def bad_abs(n): 4 | """ 5 | Calculates the absolute value of the given number. Always returns a 6 | non-negative number. 7 | """ 8 | result = -n # Oops. 9 | 10 | swear result >= 0 11 | return result 12 | 13 | def innocent_fn(): 14 | print bad_abs(-2) # OK... 15 | print bad_abs(2) # Uh-oh... 16 | 17 | def main(): 18 | innocent_fn() 19 | -------------------------------------------------------------------------------- /example/hello.vg: -------------------------------------------------------------------------------- 1 | # This is an innocent program which meets all of its moral obligations. 2 | 3 | def fib(n): 4 | """ 5 | Calculates the nth value in the Fibonacci sequence. 6 | 7 | "n" must be non-negative, and the result will be as well. 8 | """ 9 | implore n >= 0 10 | if n < 2: 11 | result = n 12 | else: 13 | result = fib(n - 1) + fib(n - 2) 14 | 15 | swear result >= 0 16 | return result 17 | 18 | def main(): 19 | print "Let's see some Fibonacci numbers!" 20 | for n in xrange(0, 10): 21 | print n, ':', fib(n) 22 | print "I feel happy and innocent!" 23 | -------------------------------------------------------------------------------- /vigil: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import re 4 | import sys 5 | import traceback 6 | 7 | source_path = sys.argv[1] 8 | source_lines = None 9 | offenders = [] 10 | 11 | def punish(line, offense): 12 | # No double jeopardy. 13 | for _, _, offend_line in offenders: 14 | if line == offend_line: return 15 | 16 | # Walk back to find the beginning of the function containing this line. 17 | start = line 18 | while start >= 0: 19 | if re.match('def ', source_lines[start]): 20 | break 21 | start -= 1 22 | 23 | # Walk forward to find the end of the function. 24 | end = line 25 | while end < len(source_lines): 26 | if re.match('^\S+', source_lines[end]): 27 | end -= 1 28 | break 29 | end += 1 30 | 31 | # Duly note those functions which hath caused offence. 32 | offenders.append((source_lines[start].strip(), offense, line)) 33 | 34 | # Clear the lines, but don't delete them. That way later failures will 35 | # have the right line number. 36 | for i in xrange(start, end + 1): 37 | source_lines[i] = '' 38 | 39 | def vigil_implore(ok, expr): 40 | if not ok: 41 | bad_line = traceback.extract_stack()[-3][1] 42 | punish(bad_line, 43 | "Denied the needs of a function which implored '%s'." % expr) 44 | 45 | def vigil_swear(ok, expr): 46 | if not ok: 47 | bad_line = traceback.extract_stack()[-2][1] 48 | punish(bad_line, "Swore '%s' and failed to provide such." % expr) 49 | 50 | def vigil_done(): 51 | # Silent vigil if all is well. 52 | if not offenders: 53 | return 54 | 55 | # Strip out the dirty impure lines. 56 | cleansed = filter(len, source_lines) 57 | with open(source_path, 'w') as f: 58 | f.writelines(cleansed) 59 | 60 | print("") 61 | print("") 62 | print("------------------------------------------------------------------") 63 | print("") 64 | print("The ever vigilant watchers of your code have found malfeasance in:") 65 | print("") 66 | 67 | for fn, offense, _ in offenders: 68 | print(fn) 69 | print("Crime:", offense) 70 | print("") 71 | 72 | print("Each has been dealt an appropriate punishment.") 73 | 74 | def vigil_uncaught(): 75 | raise_line = traceback.extract_tb(sys.exc_info()[2])[-1][1] 76 | print("uncaught error from line ", raise_line) 77 | punish(raise_line, "Raised '%s' which was not caught." % sys.exc_info()[1]) 78 | 79 | try: 80 | with open(source_path) as f: 81 | source_lines = f.readlines() 82 | 83 | source = "" 84 | for line in source_lines: 85 | line = re.sub(r'(\s*)implore (.*)', r'\1vigil_implore(\2, """\2""")', line) 86 | line = re.sub(r'(\s*)swear (.*)', r'\1vigil_swear(\2, """\2""")', line) 87 | source += line 88 | source += """ 89 | try: 90 | main() 91 | except Exception as ex: 92 | vigil_uncaught() 93 | 94 | vigil_done() 95 | """ 96 | exec(source) 97 | except: 98 | print("Vigil has failed to uphold supreme moral vigilance.") 99 | offenders = [] 100 | source_path = sys.argv[0] 101 | with open(source_path) as f: 102 | source_lines = f.readlines() 103 | vigil_uncaught() 104 | 105 | vigil_done() 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Vigil is a *very safe* programming language, and an entry in the [January 2013 PLT Games competition](http://www.pltgames.com/competition/2013/1). 2 | 3 | Many programming languages claim to take testing, contracts and safety seriously, but only Vigil is *truly* vigilant about not allowing code that fails to pass programmatic specifications. 4 | 5 | ## Syntax and semantics 6 | 7 | Vigil is very similar to Python with the minor proviso that you must provide a `main()` function which will be automatically called for you. 8 | 9 | Infinitely more important than mere syntax and semantics is its addition of **supreme moral vigilance**. This is similar to contracts, but less legal and more medieval. 10 | 11 | ### The `implore` statement to beseech your needs 12 | 13 | Often, a function will require that parameters have certain desirable properties. A function in Vigil can state what it requires by using `implore`: 14 | 15 | ```python 16 | def square_root(n): 17 | implore n >= 0 18 | return math.sqrt(n) 19 | ``` 20 | 21 | If a caller fails to provide valid arguments, it is *wrong* and must be punished. 22 | 23 | ### The `swear` statement to state what you provide in return 24 | 25 | If a good caller meets its obligations, the onus is thus on you to fulfill your end of the bargain. You can state the oaths that you promise to uphold using `swear`: 26 | 27 | ```python 28 | def fib(n): 29 | if n < 2: 30 | result = n 31 | else: 32 | result = fib(n - 1) + fib(n - 2) 33 | 34 | # fib() never returns negative number. 35 | swear result >= 0 36 | return result 37 | ``` 38 | 39 | If a function fails to uphold what it has sworn to do, it is *wrong* and must be punished. 40 | 41 | ### Unhandled exceptions 42 | 43 | It goes without saying that any function that throws an exception which isn't caught is *wrong* and must be punished. 44 | 45 | ## Runtime vigilance 46 | 47 | This is where Vigil sets itself apart from weaker languages that lack the courage of their convictions. When a Vigil program is executed, Vigil itself will monitor all oaths (implorations and swears) that have been made. If an oath is broken, the offending function (the caller in the case of `implore` and the callee in the case of `swear`) *will be duly punished.* 48 | 49 | How? 50 | 51 | **Simple: it will be deleted from your source code.** 52 | 53 | The only way to ensure your program meets its requirements is to absolutely forbid code that fails to do so. With Vigil, this shall be done for you *automatically*. After enough runs, Vigil promises that all remaining code meets its oaths. 54 | 55 | ## Usage 56 | 57 | Vigil is a command-line executable. Pass it the path to a file to run: 58 | 59 | ``` 60 | $ ./vigil example/hello.vg 61 | ``` 62 | 63 | The "example" directory has some to get you started. 64 | 65 | ## FAQ 66 | 67 | ### Is this serious? 68 | 69 | Eternal moral vigilance is no laughing matter. 70 | 71 | ### But isn't a language that deletes code crazy? 72 | 73 | No, wanting to keep code that demonstrably has bugs *according to its own specifications* is crazy. What good could it possibly serve? It is corrupted and must be cleansed from your codebase. 74 | 75 | Vigil will do this for you automatically. 76 | 77 | ### Vigil deleted a function. Won't that cause the functions that call it to fail? 78 | 79 | It would seem that those functions appear to be corrupted as well. Run Vigil again and it will take care of that for you. Several invocations may be required to fully excise all bugs from your code. 80 | --------------------------------------------------------------------------------