def load(self, board, f): contents = f.read() sizes = list(re.findall('\\GbstnTamanho{([0-9]+)}{([0-9]+)}', contents)) if len(sizes) != 1: raise basic.BoardFormatException(i18n.i18n('Malformed tex board')) width, height = board.size = int(sizes[0][0]), int(sizes[0][1]) board.head = (0, 0) board._clear_board() for coli in range(4): col = gbs_builtins.Color(coli).name() col_stones = re.findall('\\Gbstn' + col + '{([0-9]+)}{([0-9]+)}{([0-9]+)}' % (), contents) for x, y, count in col_stones: x, y, count = int(x), int(y), int(count) if x >= width or y >= height: raise basic.BoardFormatException(i18n.i18n('Malformed tex board')) board.cells[y][x].set_num_stones(coli, count) headers = list(re.findall('\\GbstnCabezal{([0-9]+)}{([0-9]+)}', contents)) if len(headers) > 1: raise basic.BoardFormatException(i18n.i18n('Malformed tex board')) elif len(headers) == 1: x, y = int(headers[0][0]), int(headers[0][1]) if x >= width or y >= height: raise basic.BoardFormatException(i18n.i18n('Malformed tex board')) board.head = y, x board.clear_changelog()
def parse_atom(self, tree): if tree.children[0] == 'type': tok = tree.children[1] args = tree.children[2] if args is None: args = [] else: args = [self.parse_atom(a) for a in args.children] if tok.value in BasicTypes: t = BasicTypes[tok.value] if t.kind_arity != len(args): msg = i18n.i18n('type "%s" expects %u parameters, but receives %u') % ( tok.value, t.kind_arity, len(args)) area = position.ProgramAreaNear(tok) raise GbsTypeSyntaxException(msg, area) return t(*args) else: if tok.value in self.context.keys(): return self.context[tok.value] else: """[TODO] Translate """ msg = i18n.i18n('Undefined type "%s".') % (tok.value,) area = position.ProgramAreaNear(tok) raise GbsTypeSyntaxException(msg, area) elif tree.children[0] == 'typeVar': tok = tree.children[1] if tok.value in self.typevars: return self.typevars[tok.value] else: fresh = GbsTypeVar(tok.value) self.typevars[tok.value] = fresh return fresh
def check(self, options): if options['src']: self.check_file_exists(options['src']) if options['from']: self.check_file_exists(options['from']) if options['lint'] not in lang.GobstonesOptions.LINT_MODES: raise OptionsException(i18n.i18n('%s is not a valid lint option.') % (options['lint'],)) if not self.check_size(options['size']): raise OptionsException(i18n.i18n('Size %s is not a valid size. Positive integers expected.') % (str(options['size']),))
def parse(self, filename, program_text): # Parse gobstones script self.api.log(i18n.i18n('Parsing.')) tree = self._parse(program_text, filename) assert tree # Explode macros self.api.log(i18n.i18n('Exploding program macros.')) self.explode_macros(tree) return GobstonesRun().initialize(tree)
def _warn_conflict(self, nonterminal, terminal, area): "Emits a warning for a conflictive state." msg = '' msg += i18n.i18n('Conflictive rule for: ("%s", "%s")\n') % ( nonterminal, terminal) msg += i18n.i18n('Will choose first production:\n') msg += utils.indent(bnf_rule_to_str( self._parse_table[(nonterminal, terminal)])) self.warn(ParserException(msg, area))
def _set_routine_definition_type(self, tree, prfn, name, params, body): """Given a context with types for the parameters and local variables in a routine, build the type for this routine and unify it with its type in the global context. For instance if the function "f" has a parameter "x", and returns an expression, take the type "s" for "x" from the local context, the type "t" for the returned expression. Build the type "s -> t" for the function and unify that with any type information previously known for "f". This requires that the body of the routine has already been typechecked.""" param_types = [] for p in params.children: param_types.append(self.context[p.value]) param_types = gbs_type.GbsTupleType(param_types) if prfn == 'procedure': def_type = gbs_type.GbsProcedureType(param_types) elif prfn == 'function': return_types = self._return_type(prfn, name, params, body) def_type = gbs_type.GbsFunctionType(param_types, return_types) elif prfn == 'entrypoint' and (name.value == 'program' or name.value == 'interactive'): def_type = gbs_type.GbsEntryPointType() else: assert False expected = self.global_context[name.value].instantiate() try: gbs_type.unify(expected, def_type) if prfn == 'function': #[TODO] Check freevars = def_type.freevars() if len(freevars) > 0: def_type = gbs_type.GbsForallType(freevars, def_type) self.global_context[name.value] = def_type tree.type_annot = def_type except gbs_type.UnificationFailedException as e: area = position.ProgramAreaNear(tree) if prfn == 'procedure': msg = i18n.i18n( 'procedure "%s" should take: %s\n' + 'But takes: %s' ) % ( name.value, expected.paramtype(), def_type.paramtype() ) else: msg = i18n.i18n( 'function "%s" should take: %s and return: %s\n' + 'But takes: %s and returns: %s' ) % ( name.value, expected.paramtype(), expected.restype(), def_type.paramtype(), def_type.restype() ) self.error(GbsTypeInferenceException(msg, area))
def _error_conflictive_definition(self, tree, name, as_type, val): if val.name() == name: area = position.ProgramAreaNear(tree) l1 = i18n.i18n('"%s" is not a ' + as_type) % (name,) l2 = i18n.i18n(val.type() + ' "%s" defined %s') % (name, val.where()) raise GbsLintException('\n'.join([l1, l2]), area) else: area = position.ProgramAreaNear(tree) msg = i18n.i18n('"%s" is too similar to ' + val.type() + ' "%s", defined %s') % ( name, val.name(), val.where()) raise GbsLintException(msg, area)
def fail(msg): raise basic.BoardFormatException( i18n.i18n("Malformed gbb board") + "\n" + " " + i18n.i18n("Near line:") + ' "' + orig[0].strip("\r\n") + '"\n' + " " + msg )
def _put_from_description(self, cell, description): coli = 0 for cn in gbs_builtins.COLOR_NAMES: if description[-1].lower() == cn[0].lower(): count = description[:-1] for l in count: if l not in '0123456789': raise basic.BoardFormatException(i18n.i18n('Malformed board')) cell.put(coli, int(count)) return coli += 1 raise basic.BoardFormatException(i18n.i18n('Malformed board'))
def _add_index(self, varName, tree): var = self.symbol_table.check_not_defined_or_defined_as(tree, varName, 'atomic', ['index', 'variable', 'parameter']) if var is None: self.symbol_table.add(gbs_constructs.UserIndex(varName, tree)) elif var.type() == 'variable': msg = i18n.i18n('Index of a foreach/repeatWith/repeat cannot be a variable: "%s"') % (varName,) area = position.ProgramAreaNear(tree) raise GbsLintException(msg, area) elif var.type() == 'parameter': msg = i18n.i18n('Index of a foreach/repeatWith/repeat cannot be a parameter: "%s"') % (varName,) area = position.ProgramAreaNear(tree) raise GbsLintException(msg, area)
def _add_var(self, varName, tree): var = self.symbol_table.check_not_defined_or_defined_as(tree, varName, 'atomic', ['variable', 'index', 'parameter']) if var is None: self.symbol_table.add(gbs_constructs.UserVariable(varName, tree)) elif var.type() == 'index': msg = i18n.i18n('Cannot modify "%s": index of a foreach/repeatWith/repeat is immutable') % (varName,) area = position.ProgramAreaNear(tree) raise GbsLintException(msg, area) elif var.type() == 'parameter': msg = i18n.i18n('Cannot modify "%s": parameter is immutable') % (varName,) area = position.ProgramAreaNear(tree) raise GbsLintException(msg, area)
def parse_error(self, nonterminal, previous_token, token): "Raises a GbstonesParserException describing a parse error." area = position.ProgramAreaNear(token) if previous_token.type == 'lowerid' and token.type == '(': raise GbsParserException(i18n.i18n('Cannot call a function here'), area) elif previous_token.type == 'upperid' and token.type == '(': raise GbsParserException(i18n.i18n('Cannot call a procedure here'), area) elif previous_token.type == 'upperid' and token.type != '(': msg = i18n.i18n('Procedure name "%s" is missing a "("') % (previous_token.value,) raise GbsParserException(msg, area) elif token.type == 'EOF': raise GbsParserException(i18n.i18n('Premature end of input'), area) bnf_parser.Parser.parse_error(self, nonterminal, previous_token, token)
def build_special_key(self): return [ self.build_key(i18n.i18n("K_ARROW_LEFT"), GobstonesKeys.ARROW_LEFT), self.build_key(i18n.i18n("K_ARROW_UP"), GobstonesKeys.ARROW_UP), self.build_key(i18n.i18n("K_ARROW_RIGHT"), GobstonesKeys.ARROW_RIGHT), self.build_key(i18n.i18n("K_ARROW_DOWN"), GobstonesKeys.ARROW_DOWN), self.build_key('K_ENTER', 13), self.build_key('K_SPACE', 32), self.build_key('K_DELETE', 46), self.build_key('K_BACKSPACE', 8), self.build_key('K_TAB', 9), self.build_key('K_ESCAPE', 27), ]
def check_unused_assignVarTuple1(self, tree): varnames = [v.value for v in tree.children[1].children] any_used = False for v in varnames: if v in tree.live_out: any_used = True break if not any_used: if len(varnames) == 1: msg = i18n.i18n('Variable "%s" defined but not used') % (varnames[0],) else: msg = i18n.i18n('Variables "(%s)" defined but not used') % ( ', '.join(varnames),) area = position.ProgramAreaNear(tree) raise GbsUnusedVarException(msg, area)
def check_return_arity(self, def_comp, tree, ret_arity): prfn = def_comp.type() name = def_comp.name() nretvals = def_comp.num_retvals() if nretvals != ret_arity: area = position.ProgramAreaNear(tree) if nretvals == 1: l1 = i18n.i18n('Function "%s" returns one value') % (name,) else: l1 = i18n.i18n('Function "%s" returns %i values') % (name, nretvals) if ret_arity == 1: l2 = i18n.i18n('One value is expected') else: l2 = i18n.i18n('%i values are expected') % (ret_arity,) raise GbsLintException('\n'.join([l1, l2]), area)
def check_constructor(self, tree): for child_tree in tree.children[2].children: self.check_expression(child_tree) def is_field_gen(node): if not len(node.children) > 0: return False if not (isinstance(node.children[0], str) and node.children[0] == 'funcCall'): return False return (isinstance(node.children[1], bnf_parser.Token) and node.children[1].value == '_mk_field') def fstop_search(node): if len(node.children) > 0 and node.children[0] == 'constructor': self.check_constructor(node) return True else: return False fieldgens = collect_nodes_with_stop(tree, tree, is_field_gen, fstop_search) field_names = [] for fieldgen in fieldgens: fname, fvalue = fieldgen.children[2].children fname = fname.children[1].value if not fname in field_names: field_names.append(fname) else: area = position.ProgramAreaNear(tree) msg = i18n.i18n('Repeated assignment for field "%s".') % (fname,) raise GbsLintException(msg, area)
def check_expression(self, tree): exptype = tree.children[0] dispatch = { 'or': self.check_binary_op, 'and': self.check_binary_op, 'not': self.check_unary_op, 'relop': self.check_binary_op, 'addsub': self.check_binary_op, 'mul': self.check_binary_op, 'divmod': self.check_binary_op, 'pow': self.check_binary_op, 'listop': self.check_binary_op, 'varName': self.check_varName, 'projection' : self.check_binary_op, 'constructor': self.check_constructor, 'funcCall': self.check_funcCall, 'unaryMinus': self.check_unary_op, 'match': self.check_match, 'literal': self.check_literal, 'atom': self.check_atom, 'type': self.check_type, } if exptype in dispatch: dispatch[exptype](tree) else: msg = i18n.i18n('Unknown expression: %s') % (exptype,) area = position.ProgramAreaNear(tree) raise GbsLintException(msg, area)
def gen_expression(self, tree): "Returns the GEN set of an expression." if tree.live_gen is not None: return tree.live_gen exptype = tree.children[0] dispatch = { 'or': self.gen_binary_op, 'and': self.gen_binary_op, 'not': self.gen_unary_op, 'relop': self.gen_binary_op, 'addsub': self.gen_binary_op, 'mul': self.gen_binary_op, 'divmod': self.gen_binary_op, 'pow': self.gen_binary_op, 'listop': self.gen_binary_op, 'projection': self.gen_binary_op_left_only, 'constructor': self.gen_funcCall, 'match': self.gen_match, 'varName': self.gen_varName, 'funcCall': self.gen_funcCall, 'unaryMinus': self.gen_unary_op, 'literal': self.gen_literal, 'type': self.gen_type, } if exptype in dispatch: tree.live_gen = dispatch[exptype](tree) else: msg = i18n.i18n('Unknown expression: %s') % (exptype,) area = position.ProgramAreaNear(tree) raise GbsLivenessException(msg, area) return tree.live_gen
def compile_expression(self, tree, code): "Compile an expression." exptype = tree.children[0] dispatch = { 'or': self.compile_or, 'and': self.compile_and, 'not': self.compile_not, 'relop': self.compile_binary_op, 'addsub': self.compile_binary_op, 'mul': self.compile_binary_op, 'divmod': self.compile_binary_op, 'pow': self.compile_binary_op, 'listop': self.compile_binary_op, 'projection': self.compile_binary_op, 'constructor': self.compile_func_call, 'varName': self.compile_var_name, 'funcCall': self.compile_func_call, 'match': self.compile_match, 'unaryMinus': self.compile_unary_minus, 'literal': self.compile_literal, 'type': self.compile_type, } if exptype in dispatch: dispatch[exptype](tree, code) else: msg = i18n.i18n('Unknown expression: %s') % (exptype,) area = position.ProgramAreaNear(tree) raise GbsCompileException(msg, area)
def parse_error(self, top, _previous_token, token): "Raises a ParserException describing a parse error." if is_nonterminal(top): follow = self._followups(top) else: follow = [Token.type_description(top)] if len(follow) == 1: msg = i18n.i18n('Found: %s\nExpected: %s') % (token, follow[0]) else: msg = '' msg += i18n.i18n('\n'.join([ 'Found: %s', 'Expected one of the following tokens:'])) % ( token,) msg += '\n' + utils.indent('\n'.join(follow)) raise ParserException(msg, position.ProgramAreaNear(token))
def check(self, tree): # Check semantics self.api.log(i18n.i18n('Performing semantic checks.')) self.lint(tree, strictness=self.options.lint_mode, allow_recursion=self.options.allow_recursion) # Check liveness if self.options.check_liveness: self.check_live_variables(tree)
def prelude_for_file(filename): prelude_basename = i18n.i18n('Prelude') + '.gbs' prelude_filename = os.path.join(os.path.dirname(filename), prelude_basename) if os.path.exists(prelude_filename) and os.path.basename(filename) != prelude_basename: return prelude_filename else: return None
def infer_expression(self, tree): "Infer types for an expression." exptype = tree.children[0] dispatch = { 'or': self.infer_bool_bool_bool_binary_op, 'and': self.infer_bool_bool_bool_binary_op, 'not': self.infer_bool_bool_unary_op, 'relop': self.infer_a_a_bool_binary_op, 'addsub': self.infer_int_int_int_binary_op, 'mul': self.infer_int_int_int_binary_op, 'divmod': self.infer_int_int_int_binary_op, 'pow': self.infer_int_int_int_binary_op, 'listop': self.infer_list_list_list_binary_op, 'projection': self.infer_projection, 'constructor': self.infer_constructor, 'varName': self.infer_var_name, 'funcCall': self.infer_func_call, 'match': self.infer_match, 'unaryMinus': self.infer_a_a_unary_op, 'literal': self.infer_literal, 'type': self.infer_type, } if exptype in dispatch: return dispatch[exptype](tree) else: msg = i18n.i18n('Unknown expression: %s') % (exptype,) area = position.ProgramAreaNear(tree) self.error(GbsTypeInferenceException(msg, area))
def check_unused_assignVarName(self, tree, var=None): if var is None: var = tree.children[1].children[1] if var.value not in tree.live_out: msg = i18n.i18n('Variable "%s" defined but not used') % (var.value,) area = position.ProgramAreaNear(tree) raise GbsUnusedVarException(msg, area)
def check_function_definition(self, tree): prfn, name, params, body, typeDecl = tree.children if body.children == []: name = name.value area = position.ProgramAreaNear(tree) msg = i18n.i18n('function body of "%s" cannot be empty') % (name,) raise GbsLintException(msg, area) elif not self._body_has_return(body): name = name.value area = position.ProgramAreaNear(body.children[-1]) msg = i18n.i18n('function "%s" should have a return') % (name,) raise GbsLintException(msg, area) return_clause = body.children[-1] if self._return_is_empty(return_clause): name = name.value area = position.ProgramAreaNear(body.children[-1]) raise GbsLintException(i18n.i18n('return from function "%s" must return something') % (name,), area)
def run_object_code(self, compiled_program, initial_board): # Make runnable runnable = self.make_runnable(compiled_program) # Run self.api.log(i18n.i18n('Starting program execution.')) rtn_vars, final_board = runnable.run(initial_board.clone(), self.api) gbs_run = GobstonesRun().initialize(None, compiled_program, initial_board, final_board.value, runnable, rtn_vars) return gbs_run
def backtrace(self, msg): def describe(ar, indent_): loc = ar.routine.nearby_elems.get(ar.ip, self.program.tree).pos_begin.file_row() return '%s%s %s %s' % (' ' * indent_, ar.routine.prfn, ar.routine.name, loc) cs = self.callstack + [self.ar] res = '' res += msg + '\n\n' res += i18n.i18n('At:') + '\n' res += indent('\n'.join([ describe(x, y) for x, y in zip(cs, range(0, len(cs))) ])) + '\n' bindings = [(k, v) for k, v in seq_sorted(self.ar.bindings.items()) if k[0] != '_'] if len(bindings) > 0: res += i18n.i18n('Locals:') + '\n' res += indent('\n'.join(['%s: %s' % (k, v) for k, v in bindings])) return res
def constructor_except(real_type, expected_type): area = position.ProgramAreaNear(tree) msg = i18n.i18n( 'constructor "%s" is receiving: %s\n' + 'But should receive: %s' ) % ( expected_type.name, real_type.fields_repr(), expected_type.fields_repr() ) self.error(GbsTypeInferenceException(msg, area))
def compile(self, filename, program_text): gbs_run = self.parse(filename, program_text) tree = gbs_run.tree # Check semantics, liveness and types self.check(tree) # Compile program self.api.log(i18n.i18n('Compiling.')) gbs_run.compiled_program = self.compile_program(tree) return gbs_run
def _check_excluded_types(self, tree, type, excluded_types): for excluded_type in excluded_types: try: gbs_type.unify(type, excluded_type) area = position.ProgramAreaNear(tree) msg = i18n.i18n('Expression can\'t have type: %s') % (excluded_type,) self.error(GbsTypeInferenceException(msg, area)) except gbs_type.UnificationFailedException as exception: pass