def parse(e, z, error): p = c_macro() match = None match = e_macro.search(error.code) if not match: errors.add(e, error, errors.ERRORS_FATAL, "the macro format is absolutely not understandable.\n") return None if len(match.group('spaces_beforesharp')) != 0: errors.add(e, error, errors.ERRORS_STYLE, "the '#' character must be placed at the beginning " \ "of the line.\n") p.indentation = len(match.group('spaces_aftersharp')) if match.group('macro') == "if": p.type = MACRO_IF elif match.group('macro') == "else": p.type = MACRO_ELSE elif match.group('macro') == "endif": p.type = MACRO_ENDIF elif match.group('macro') == "define": p.type = MACRO_DEFINE elif match.group('macro') == "undef": p.type = MACRO_UNDEF elif match.group('macro') == "ifdef": p.type = MACRO_IFDEF elif match.group('macro') == "ifndef": p.type = MACRO_IFNDEF elif match.group('macro') == "include": p.type = MACRO_INCLUDE # try: # if len(match.group('spaces_aftermacro')) != 1 and match.group('macro') == 'include': # errors.add(e, error, errors.ERRORS_STYLE, # "#%s MUST have one whitespace after it\n" % match.group('macro')) # except: # pass p.match = match if p.type == MACRO_INCLUDE: p.name = match.group('include') elif p.type == MACRO_DEFINE or p.type == MACRO_UNDEF or \ p.type == MACRO_IFDEF or p.type == MACRO_IFNDEF: p.name = match.group('defined_name') else: p.name = None if p.type == MACRO_DEFINE: p.arguments = match.group('define_args') p.body = match.group('define_body') else: p.arguments = None p.body = None return p
def fields(e, z, p, error): match = None nfields = 0 nlines = 0 m = None i = None match = e_a_fields.findall(p.body) if not match: return nlines = len(match) match = e_fields.findall(p.body) if not match: return for m in match: nfields += 1 if m: nfields += len(m.lstrip(",").split(",")) for i in range(0, nfields - nlines): errors.add(e, error, errors.ERRORS_STYLE, "one of the structure's fields is not alone on its line.\n")
def check(e): ## structures.check(e) ## enumerations.check(e) ## unions.check(e) # trailings(e.code) # columns(e.code) error = classes.c_error(e.parser.old_contents) errors.open(e, error) if (e.parser.windows_style): errors.add(e, error, errors.ERRORS_STYLE, "This file contains \\r at end of lines !\n") columns(e, error) trailings(e, error) errors.close(e, error) errors.commit(e, error) types.check(e) #print "types done" globals.check(e) #print "globals done" comments.check(e) #print "comments done" macros.check(e) #print "macros done" functions.check(e) #print "func done" prototypes.check(e) #print "proto done" contents.check(e)
def lines(e, z, p, error): nlines = None d = None b = None d = e_lines.sub("", p.declarations).rstrip() b = e_lines.sub("", p.body).rstrip() nlines = -1 for line in d.split("\n") + b.split("\n"): match = e_empty_line.search(line) if not match: nlines += 1 if nlines > functions.FUNCTIONS_LINE_EXTREME_LIMIT: errors.add(e, error, errors.ERRORS_FATAL, "the function contains more than " + \ str(functions.FUNCTIONS_LINE_EXTREME_LIMIT) + " lines. are you " \ "kidding us? (%i faults !!!!)\n" % errors.ERRORS_FATAL) elif nlines > functions.FUNCTIONS_LINE_LIMIT: errors.add(e, error, nlines - functions.FUNCTIONS_LINE_LIMIT, "the function contains %i lines. expected %i (%i faults)\n" % (nlines, functions.FUNCTIONS_LINE_LIMIT, nlines - functions.FUNCTIONS_LINE_LIMIT))
def trailings(e, error): match = None m = None match = e_whitespace.findall(error.code) for m in match: errors.add(e, error, errors.ERRORS_STYLE, "a line is containing one or more trailing whitespaces.\n")
def alignment(e, z, p, error): match = None m = None match = e_a_fields.findall(p.body) for m in match: if p.a_fields != len(m[0]): errors.add(e, error, errors.ERRORS_STYLE, "the structure definition's member '" + m[1] + \ "' is not aligned with the others.\n")
def declarations_init(e, z, p, error): match = None m = None match = e_call.findall(p.declarations) if not match: return for m in match: errors.add(e, error, errors.ERRORS_STYLE, "local variables must not be initialized by function " \ "or macro-function calls.\n")
def columns(e, error): lines = None l = None lines = error.code.split("\n") e_header_fuckup = re.compile('^\*\* .+ for .+ in .+$') for l in lines: if len(l) >= COLUMNS_LIMIT and not e_header_fuckup.search(l): errors.add(e, error, errors.ERRORS_STYLE, "a line is exceeding the " + str(COLUMNS_LIMIT) + \ " columns limit.\n")
def parse(e, z, error): p = c_comment() match = None match = e_comment.search(error.code) if not match: errors.add(e, error, errors.ERRORS_STYLE, "the comment is not properly formatted.\n") return None return p
def grade_student(self, student, i_student, n_students): """ Function: grade_student ----------------------- Grades a particular student. Outputs the results to a file. student: The student's name. """ log("\n\n%s (%d/%d):" % (student, i_student, n_students)) # Check to see that this student exists. If not, skip this student. path = ASSIGNMENT_DIR + self.assignment + "/" + STUDENT_DIR + student + \ "-" + self.assignment + "/" if not os.path.exists(path): err("Student " + student + " does not exist or did not submit!") return # Graded output for this particular student. Add it to the overall output. output = {"name": student, "files": {}, "got_points": 0} self.o.fields["students"].append(output) # Parse student's response. response = {} for filename in self.files: # Add this file to the graded output. graded_file = { "filename": filename, "problems": [], "errors": [], "got_points": 0 } output["files"][filename] = graded_file fname = path + filename try: f = open(fname, "r") # Run their files through the stylechecker to make sure it is valid. Add # the errors to the list of style errors for this file and overall for # this student. graded_file["errors"] += StyleChecker.check(f) # Reset back to the beginning of the file. f.seek(0) response[filename] = iotools.parse_file(f) f.close() # If the file does not exist, then they get 0 points. except IOError: add(graded_file["errors"], FileNotFoundError(fname)) # Grade this student, make style deductions, and output the results. output["got_points"] = self.grader.grade(response, output) formatter.format_student(student, output, self.specs, self.hide_solutions)
def declarations_alignment(e, z, p, error): match = None type = -1 name = -1 m = None match = e_a_declarations.findall(p.declarations) for m in match: if p.a_declarations != len(m[0]): errors.add(e, error, errors.ERRORS_STYLE, "the block declaration's member '" + m[1] + \ "' is not aligned with the function name.\n")
def declarations_format(e, z, p, error): match = None nlines = 0 ndecs = 0 m = None i = None match = e_a_declarations.findall(p.declarations) if not match: return diff = p.declarations.count(';') - p.declarations.count('\n') - 1 if diff > 0: for i in range(0, diff): errors.add(e, error, errors.ERRORS_STYLE, "one of the declaration is not alone on its line.\n")
def values(e, z, p, error): match = None nvalues = 0 nlines = 0 m = None i = None match = e_a_values.findall(p.body) if not match: return nlines = len(match) nvalues = len(p.body.split(",")) for i in range(0, nvalues - nlines): errors.add(e, error, errors.ERRORS_STYLE, "one of the enumeration's values is not alone on its line.\n")
def header(e, z, i): error = classes.c_error(i) match = None errors.open(e, error) if not error.code: errors.add(e, error, errors.ERRORS_STYLE, "the file does not contains any header.\n") else: match = e_header.search(error.code) if not match: errors.add(e, error, errors.ERRORS_STYLE, "the file header is not properly formatted.\n") checker.columns(e, error) errors.close(e, error) errors.commit(e, error)
def alignment(e, z, p, error): match = None a_type = -1 a_name = -1 m = None for m in e_a_argument.finditer(p.arguments): if a_type == -1 and a_name == -1: a_type = p.a_arguments + len(m.group('a_type')) a_name = a_type + len(m.group('a_var')) continue if a_type != len(m.group('a_type')): errors.add(e, error, errors.ERRORS_STYLE, "prototype argument's type '" + m.group('type') + "' is not aligned with the others.\n") if m.group('name') and a_name != len(m.group('a_var')): errors.add(e, error, errors.ERRORS_STYLE, "prototype argument's name '" + m.group('name') + "' is not aligned with the others.\n")
def parse(e, z, error): p = c_union() match = None match = e_union.search(error.code) if not match: errors.add(e, error, errors.ERRORS_FATAL, "the union format is absolutely not understandable.\n") return None if len(match.group(1)) != 0: errors.add(e, error, errors.ERRORS_WARNING, "the keyword 'union' should be placed at the " \ "beginning of the line.\n") p.name = match.group(3) p.body = match.group(4) p.a_fields = len(match.group(1)) + len("union") + len(match.group(2)) return p
def alignment(e, z, p, error): match = None a_type = -1 a_name = -1 m = None for m in e_a_argument.finditer(p.arguments): if a_type == -1 and a_name == -1: a_type = p.a_arguments + len(m.group('a_type')) a_name = a_type + len(m.group('a_var')) continue if a_type != len(m.group('a_type')): errors.add( e, error, errors.ERRORS_STYLE, "prototype argument's type '" + m.group('type') + "' is not aligned with the others.\n") if m.group('name') and a_name != len(m.group('a_var')): errors.add( e, error, errors.ERRORS_STYLE, "prototype argument's name '" + m.group('name') + "' is not aligned with the others.\n")
def parse(e, z, error): p = c_enumeration() match = None match = e_enumeration.search(error.code) if not match: errors.add(e, error, errors.ERRORS_FATAL, "the enumeration format is absolutely not understandable.\n") return None if len(match.group(1)) != 0: errors.add(e, error, errors.ERRORS_WARNING, "the keyword 'enum' should be placed at the " \ "beginning of the line.\n") p.name = match.group(3) p.body = match.group(4) p.a_values = len(match.group(1)) + len("enum") + len(match.group(2)) return p
def alignment(e, z, p, error): alignment = -1 match = None m = None if p.type == MACRO_ENDIF: z.indentation = z.indentation - 1 if p.indentation != z.indentation: if p.indentation != z.indentation - 1 and p.type == MACRO_ELSE: errors.add(e, error, errors.ERRORS_STYLE, "the macro indentation is wrong; expecting " + \ str(z.indentation - 1) + " whitespaces.\n") elif p.type != MACRO_ELSE: errors.add(e, error, errors.ERRORS_STYLE, "the macro indentation is wrong; expecting " + \ str(z.indentation) + " whitespaces.\n") if p.type == MACRO_IFNDEF or p.type == MACRO_IFDEF or p.type == MACRO_IF: z.indentation = z.indentation + 1 match = e_a_breakers.findall(error.code) for m in match: if alignment == -1: alignment = len(m) if alignment != len(m): errors.add(e, error, errors.ERRORS_STYLE, "one of the line breakers is not aligned.\n")
def arguments(e, z, p, error): match = None nlines = 0 nargs = 0 i = None match = e_a_argument.findall(p.arguments) for match in e_a_argument.finditer(p.arguments): nlines += 1 if match.group('spc2'): errors.add( e, error, errors.ERRORS_STYLE, "%s : there MUST NOT be any spaces before the , or the" ")\n" % p.name) if not match.group('spc1') and match.group('name'): errors.add( e, error, errors.ERRORS_STYLE, "there MUST be spaces between a type and an identifier\n") nargs = len(p.arguments.split(",")) for i in range(0, nargs - nlines): errors.add( e, error, errors.ERRORS_STYLE, "%s : one of the prototype's argument is not alone on its" " line.\n" % p.name)
def parse(e, z, error): p = c_prototype() match = None match = e_prototype.search(error.code) p.code = error.code if not match: print p.code errors.add(e, error, errors.ERRORS_FATAL, "the prototype format is absolutely not understandable.\n") return None if match.group('qual') == 'static': p.type = PROTO_TYPE_STATIC else: p.type = PROTO_TYPE_EXTERN if match.group('name'): p.name = match.group('name') p.arguments = match.group('args') p.a_arguments = len(match.group('align')) if match.group('spc1'): errors.add( e, error, errors.ERRORS_STYLE, "there MUST NOT be spaces between the function name" " and the (\n") if match.group('spc2'): errors.add(e, error, errors.ERRORS_STYLE, "there MUST NOT be spaces between the ) and ;\n") return p
def parse(e, z, error): p = c_prototype() match = None match = e_prototype.search(error.code) p.code = error.code if not match: print p.code errors.add(e, error, errors.ERRORS_FATAL, "the prototype format is absolutely not understandable.\n") return None if match.group('qual') == 'static': p.type = PROTO_TYPE_STATIC else: p.type = PROTO_TYPE_EXTERN if match.group('name'): p.name = match.group('name') p.arguments = match.group('args') p.a_arguments = len(match.group('align')) if match.group('spc1'): errors.add(e, error, errors.ERRORS_STYLE, "there MUST NOT be spaces between the function name" " and the (\n") if match.group('spc2'): errors.add(e, error, errors.ERRORS_STYLE, "there MUST NOT be spaces between the ) and ;\n") return p
def arguments_format(e, z, p, error): match = None nlines = 0 nargs = 0 i = None match = e_a_argument.findall(p.arguments) if not match: return nlines = len(match) nargs = len(p.arguments.split(",")) if nargs > functions.FUNCTIONS_ARGUMENT_LIMIT: errors.add(e, error, errors.ERRORS_STYLE, "the function contains more than " + \ str(functions.FUNCTIONS_ARGUMENT_LIMIT) + " arguments.\n") for i in range(0, nargs - nlines): errors.add(e, error, errors.ERRORS_STYLE, "one of the function's argument is not alone on its line.\n")
def parse(e, z, error): p = c_structure() match = None match = e_structure.search(error.code) if not match: errors.add(e, error, errors.ERRORS_FATAL, "the structure format is absolutely not understandable.\n") print error.code return None if len(match.group(1)) != 0: errors.add(e, error, errors.ERRORS_WARNING, "the keyword 'struct' should be placed at the " \ "beginning of the line.\n") p.name = match.group(3) p.body = match.group(4) p.a_fields = len(match.group(1)) + len("struct") + len(match.group(2)) return p
def preprocess(self): """ Function: preprocess -------------------- Check for certain things before running the tests and add them to the graded problem output. This includes: - Comments - Checking their SQL for certain keywords - Printing out their actual SQL """ # Comments and SQL. self.output["comments"] = self.response.comments self.output["sql"] = self.response.sql # Check if they included certain keywords. if self.specs.get("keywords"): missing = [] for keyword in self.specs["keywords"]: if keyword not in self.response.sql: missing.append(keyword) # Add the missing keywords to the graded output. if len(missing) > 0: add(self.output["errors"], MissingKeywordError(missing))
def arguments_alignment(e, z, p, error): match = None type = -1 name = -1 m = None match = e_a_argument.findall(p.arguments) for m in match: if type == -1 and name == -1: type = p.a_arguments + len(m[0]) name = type + len(m[1]) + len(m[2]) + len(m[3]) + len(m[4]) continue if type != len(m[0]): errors.add(e, error, errors.ERRORS_STYLE, "function argument's type '" + m[2] + \ "' is not aligned with the others.\n") if name != (len(m[0]) + len(m[1]) + len(m[2]) + len(m[3]) + len(m[4])): errors.add(e, error, errors.ERRORS_STYLE, "function argument's name '" + m[5] + \ "' is not aligned with the others.\n")
def arguments_format(e, z, p, error): match = None nlines = 0 nargs = 0 i = None match = e_a_argument.findall(p.arguments) if not match: return nlines = len(match) nargs = len(p.arguments.split(",")) if nargs > functions.FUNCTIONS_ARGUMENT_LIMIT: errors.add(e, error, errors.ERRORS_STYLE, "the function contains more than " + \ str(functions.FUNCTIONS_ARGUMENT_LIMIT) + " arguments.\n") for i in range(0, nargs - nlines): errors.add( e, error, errors.ERRORS_STYLE, "one of the function's argument is not alone on its line.\n")
def name(e, z, p, error): args = None a = None if not p.type == MACRO_DEFINE and not p.type == MACRO_UNDEF and \ not p.type == MACRO_IFDEF and not p.type == MACRO_IFNDEF: return if p.name: if p.match.group('macro') in ['define']: if not p.name.isupper(): errors.add(e, error, errors.ERRORS_STYLE, "the macro name '" + p.name + "'is not capitalized.\n") if p.arguments: args_orig = p.arguments.replace('(', '', 1) args_orig = args_orig.replace(')', '', 1) args = args_orig.split(",") for a in args: if not e_macro_argument.search(a): errors.add(e, error, errors.ERRORS_STYLE, "the macro argument name '" + a + \ "' is not capitalized.\n")
def declarations_blanks(e, z, p, error): declarations = None e_blank = re.compile( '(?P<all>(?P<declarations>.*;)[ \t]*\n(?P<ending_blanks>[ \n]*))', re.DOTALL) e_blank_line = re.compile('^[ \t]*$') m = e_blank.search(p.declarations) if m: declarations = p.declarations.replace(m.group('all'), m.group('declarations'), 1) if m.group('ending_blanks').count('\n') > 1: errors.add(e, error, errors.ERRORS_STYLE, "the declaration block and the function's body must " \ "be separated by a single blank line.\n") else: errors.add(e, error, errors.ERRORS_STYLE, "the declaration block and the function's body must " \ "be separated by a single blank line.\n") declarations = p.declarations ## if p.declarations[len(p.declarations) - 2] != '\n': ## errors.add(e, error, errors.ERRORS_STYLE, ## "the declaration block and the function's body must " \ ## "be separated by a blank line.\n") ## if p.declarations[len(p.declarations) - 3] == '\n': ## errors.add(e, error, errors.ERRORS_STYLE, ## "the declaration block and the function's body must " \ ## "be separated by a single blank line.\n") #declarations = e_lines.sub("", p.declarations) ## if p.declarations.rstrip("\n") != declarations.rstrip("\n"): ## errors.add(e, error, errors.ERRORS_STYLE, ## "the declaration block must not contain blank lines.\n") ## p.declarations = declarations; if e_blank_line.search(declarations): errors.add(e, error, errors.ERRORS_STYLE, "the declaration block must not contain blank lines.\n") #p.declarations = declarations; p.declarations = declarations
def declarations_blanks(e, z, p, error): declarations = None e_blank = re.compile('(?P<all>(?P<declarations>.*;)[ \t]*\n(?P<ending_blanks>[ \n]*))', re.DOTALL) e_blank_line = re.compile('^[ \t]*$') m = e_blank.search(p.declarations) if m: declarations = p.declarations.replace(m.group('all'), m.group('declarations'), 1) if m.group('ending_blanks').count('\n') > 1: errors.add(e, error, errors.ERRORS_STYLE, "the declaration block and the function's body must " \ "be separated by a single blank line.\n") else: errors.add(e, error, errors.ERRORS_STYLE, "the declaration block and the function's body must " \ "be separated by a single blank line.\n") declarations = p.declarations ## if p.declarations[len(p.declarations) - 2] != '\n': ## errors.add(e, error, errors.ERRORS_STYLE, ## "the declaration block and the function's body must " \ ## "be separated by a blank line.\n") ## if p.declarations[len(p.declarations) - 3] == '\n': ## errors.add(e, error, errors.ERRORS_STYLE, ## "the declaration block and the function's body must " \ ## "be separated by a single blank line.\n") #declarations = e_lines.sub("", p.declarations) ## if p.declarations.rstrip("\n") != declarations.rstrip("\n"): ## errors.add(e, error, errors.ERRORS_STYLE, ## "the declaration block must not contain blank lines.\n") ## p.declarations = declarations; if e_blank_line.search(declarations): errors.add(e, error, errors.ERRORS_STYLE, "the declaration block must not contain blank lines.\n") #p.declarations = declarations; p.declarations = declarations
def arguments(e, z, p, error): match = None nlines = 0 nargs = 0 i = None match = e_a_argument.findall(p.arguments) for match in e_a_argument.finditer(p.arguments): nlines += 1 if match.group('spc2'): errors.add(e, error, errors.ERRORS_STYLE, "%s : there MUST NOT be any spaces before the , or the" ")\n" % p.name) if not match.group('spc1') and match.group('name'): errors.add(e, error, errors.ERRORS_STYLE, "there MUST be spaces between a type and an identifier\n") nargs = len(p.arguments.split(",")) for i in range(0, nargs - nlines): errors.add(e, error, errors.ERRORS_STYLE, "%s : one of the prototype's argument is not alone on its" " line.\n" % p.name)
def type_error(e, error, typename, msg): errors.add(e, error, errors.ERRORS_STYLE, "In type " + typename + ": " + msg + "\n")
def scope(e, z, error): if e.parser.type != parsers.TYPE_HEADER: errors.add(e, error, errors.ERRORS_STYLE, "structures must be defined in header files.\n")
def parse(e, z, error): global str p = functions.c_function() match = None match = e_function.match(error.code) if not match: errors.add(e, error, errors.ERRORS_FATAL, "the function format is absolutely not understandable.\n") return None p.name = match.group('funcname') error.name = p.name p.arguments = match.group('arguments') p.a_arguments = len(match.group('arg_align')) p.a_declarations = len(match.group('funcname_align')) p.declarations = match.group('declarations') p.body = match.group('body') if len(match.group('incorrect_spce')) > 0: errors.add(e, error, errors.ERRORS_STYLE, "function declaration MUST NOT contain spaces before (\n") ########################################### zone = p.declarations + p.body common.check_id_validity(e, error, p.name) if match.group('wrong_star'): errors.add(e, error, errors.ERRORS_STYLE, "* MUST NOT be next to the type name\n") if len(match.group('lead_spce')) != 0: errors.add(e, error, errors.ERRORS_STYLE, "function return type must begin on the first column\n") # , for m in e_comma.finditer(zone): if len(m.group('next_spce')) != 1: if len(m.group('next_spce')) > 0 and m.group('next_spce')[0] != '\n': errors.add(e, error, errors.ERRORS_STYLE, ", MUST be followed by an only whitespace\n") if len(m.group('prev_spce')) > 0: errors.add(e, error, errors.ERRORS_STYLE, ", MUST NOT have whitespaces before it\n") # ; indent = 2 for line in p.body.split('\n'): if e_bracket_status.search(line): errors.add(e, error, errors.ERRORS_STYLE, "{ or } MUST be on their own line\n") for m in e_function_call.finditer(line): name = m.group('fname') if name not in ['if', 'for', 'while', 'sizeof', 'return', 'switch', 'case']: if len(m.group('spaces')) > 0: errors.add(e, error, errors.ERRORS_STYLE, "function calls MUST NOT have spaces between the name and the (\n") cast = e_cast.search(line) if cast: found = False if e.options.cast_ignore: for func_pattern in e.options.cast_ignore: if re.search(func_pattern, line): found = True break if not found and not cast.group('sizeof'): errors.add(e, error, errors.ERRORS_STYLE, "explicit cast is forbidden by the CSS\n") for line in zone.split('\n'): line += '\n' ct = line.count(';') oper = e_keywords.search(line) for m in e_semi.finditer(line): if len(m.group('prev_spce')) > 0 and m.group('anything_prev') != '': errors.add(e, error, errors.ERRORS_STYLE, "; MUST NOT have whitespaces before it\n") if oper and oper.group('keyword') == 'for' and ct >= 2: continue if ct > 2: errors.add(e, error, errors.ERRORS_STYLE, "Only one instruction is allowed per line\n") # for m in e_semi.finditer(line): # if len(m.group('prev_spce')) > 0: # errors.add(e, error, errors.ERRORS_STYLE, # "; MUST NOT have whitespaces before it\n") for m in e_keywords_error.finditer(zone): if m.group('error') != '(' and m.group('error') != ';': errors.add(e, error, errors.ERRORS_STYLE, "%s keyword MUST have its argument between parenthesis\n" % m.group('keyword')) # keywords for m in e_keywords.finditer(zone): if len(m.group('spce')) == 1 and m.group('spce')[0] == ' ': pass # it's what we want else: errors.add(e, error, errors.ERRORS_STYLE, "%s keyword MUST be followed by a whitespace\n" % m.group('keyword')) # Most of the binary operators (regexp limit some tests) for m in e_binop.finditer(zone): op = m.group('op') if op == '-' or op == '&' or op == '*': pass ## FIXME : How to parse operators that are both unaries and binaries with simple regexp ? elif op == '!' or op == '~': if len(m.group('next_spce')) > 0: errors.add(e, error, errors.ERRORS_STYLE, "operator %s must have exactly zero space on the right\n" % op) elif op == '.' or op == '->': if len(m.group('prec_spce')) > 0: errors.add(e, error, errors.ERRORS_STYLE, "operator %s must have exactly zero space on the left\n" % op) if len(m.group('next_spce')) > 0: errors.add(e, error, errors.ERRORS_STYLE, "operator %s must have exactly zero space on the right\n" % op) elif op == '++' or op == '--': pass else: if len(m.group('prec_spce')) != 1: # FIXME manque le test de si # c'est une espace errors.add(e, error, errors.ERRORS_STYLE, "operator %s must have exactly one space on the left\n" % op) if (len(m.group('next_spce')) > 1 and m.group('next_spce')[0] != '\n') or len(m.group('next_spce')) == 0: errors.add(e, error, errors.ERRORS_STYLE, "operator %s must have exactly one space on the right or a newline\n" % op) ####################################################### if match.group(2): z.locals += 1 else: z.exports += 1 if z.exports > functions.FUNCTIONS_EXPORT_LIMIT: errors.add(e, error, errors.ERRORS_STYLE, "the file contains more than " + \ str(functions.FUNCTIONS_EXPORT_LIMIT) + \ " exported \n") if (z.locals + z.exports) > functions.FUNCTIONS_FILE_LIMIT: errors.add(e, error, errors.ERRORS_STYLE, "the file contains more than " + \ str(functions.FUNCTIONS_FILE_LIMIT) + " functions.\n") return p
def scope(e, z, error): if e.parser.type != parsers.TYPE_SOURCE: errors.add(e, error, errors.ERRORS_STYLE, "functions must be defined in header files.\n")
def grade(self): """ Function: grade --------------- Runs all the tests for a particular problem and computes the number of points received for the student's response. returns: The number of points received for this response. """ # Run each test for the problem. for test in self.specs["tests"]: lost_points = 0 graded_test = { "errors": [], "deductions": [], "success": SuccessType.FAILURE } self.output["tests"].append(graded_test) # Set a new connection timeout if specified. if test.get("timeout"): self.db.get_db_connection(test["timeout"]) # Grade the test with the specific handler. try: lost_points += self.grade_test(test, graded_test) # If their query times out, restart the connection and output an error. # Retry their query first (so all queries are tried at most twice). except TimeoutError as e: print "[timed out, trying again]" self.db.kill_query() self.db.get_db_connection(test.get("timeout"), False) add(self.output["errors"], e) # Retry their query. If it still doesn't work, then give up. try: lost_points += self.grade_test(test, graded_test) except TimeoutError as e: lost_points += test["points"] self.db.kill_query() self.db.get_db_connection(test.get("timeout"), False) self.output["got_points"] = 0 continue # If there was a database error, print out the error that occurred. except DatabaseError as e: lost_points += test["points"] add(self.output["errors"], e) # Run the teardown query no matter what. finally: try: if test.get("teardown"): # print("RUNNING TEARDOWN FROM PROBLEMTYPES") self.db.execute_sql(test["teardown"]) except DatabaseError as e: lost_points += test["points"] add(self.output["errors"], e) # Apply deductions. if graded_test.get("deductions"): (deductions, errors) = self.get_errors(graded_test["deductions"], test["points"]) self.output["errors"] += errors lost_points += deductions self.got_points -= lost_points points = test["points"] - lost_points graded_test["got_points"] = points if points > 0 else 0 # Get the total number of points received. self.got_points = (self.got_points if self.got_points > 0 else 0) self.output["got_points"] = self.got_points return self.got_points
def check_id_validity(e, error, id): if not e_correct_id.search(id): # incorrect id errors.add(e, error, errors.ERRORS_STYLE, "the id \'" + id + "\' is incorrectly formatted\n")
def check_enum_field_validity(e, error, enumf): if not e_correct_enumf.search(enumf): errors.add(e, error, errors.ERRORS_STYLE, "the enumeration field \'" + enumf + "\' is incorrectly formatted\n")
def scope(e, z, p, error): if p.type == PROTO_TYPE_EXTERN: if e.parser.type != parsers.TYPE_HEADER: errors.add(e, error, errors.ERRORS_STYLE, "prototypes must be defined in header files.\n")
def grade(self, response, output): """ Function: grade --------------- Grades a student's responses. response: The student's response. output: The graded output. returns: The number of points received for this problem. """ # Grade the files (that exist) for this student. total_points = 0 processed_files = [] for f in self.specs["files"]: # Skip this file if it doesn't exist. if f not in response.keys(): if VERBOSE_LEVEL > 0: print("No file %s in student submission; skipping." % f) continue log("\n - " + f + ": ") (responses, graded_file) = (response[f], output["files"][f]) got_points = 0 if VERBOSE_LEVEL > 0: print("Submission %s contains responses for problems: %s" % (f, ",".join([num for num in responses]))) # Do we need to do any setup for this file? filespec = self.specs[f] if isinstance(filespec, dict): if "tests" not in filespec: err("Spec for file %s has no \"tests\"!" % f, true) problems = filespec["tests"] # If there is any setup for this file, do it. if "setup" in filespec: for item in filespec["setup"]: if item["type"] == "source": if VERBOSE: print("Sourcing file %s" % item["file"], end='') self.db.source_file(self.assignment, item["file"]) elif item["type"] == "queries": if VERBOSE: print("Running initial queries:\n * %s" % '\n * '.join(item["queries"])) for q in item["queries"]: self.db.execute_sql(q) else: err("Unrecognized setup item type \"%s\" for file %s" % (item["type"], f), true) else: # The problems are just in a list for the file. problems = filespec # Grade each problem in the assignment. for problem in problems: # Add this graded problem to the list in the graded file. num = problem["number"] graded_problem = { "num": num, "tests": [], "errors": [], "got_points": 0 } graded_file["problems"].append(graded_problem) try: # Check to see if the response is actually blank. (They included the # problem header but did not put anything below). if len(responses[num].sql.strip()) == 0: raise KeyError # Call the grade function on the specific class corresponding to this # problem type. grade_fn = PROBLEM_TYPES[problem["type"]] grade_fn = grade_fn(self.assignment, self.db, problem, responses[num], graded_problem) grade_fn.preprocess() # Run dependent query. self.run_dependencies(problem, response, processed_files) got_points += grade_fn.grade() except DependencyError as e: add(graded_problem["errors"], e) # If they didn't do a problem, indicate that it doesn't exist. except KeyError: graded_problem["notexist"] = True except Exception: raise # Run teardown queries. finally: self.run_teardown(problem) log(".") processed_files.append(f) # Compute total points for this file. graded_file["got_points"] = got_points total_points += got_points return total_points