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 = common.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 = common.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 load(self, board, f): contents = f.read() sizes = list(re.findall('\\GbstnTamanho{([0-9]+)}{([0-9]+)}', contents)) if len(sizes) != 1: raise lang.board.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 = lang.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 lang.board.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 lang.board.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 lang.board.basic.BoardFormatException(i18n.i18n('Malformed tex board')) board.head = y, x board.clear_changelog()
def start(self, filename, program_text, initial_board_string, run_mode): board = tools.board_format.from_string(initial_board_string) if run_mode == XGobstonesWorker.RunMode.ONLY_CHECK: options = lang.GobstonesOptions() else: options = lang.GobstonesOptions() self.gobstones = lang.Gobstones(options, self.api) try: if run_mode == XGobstonesWorker.RunMode.FULL: self.success(self.gobstones.run(filename, program_text, board)) else: # Parse gobstones script self.gobstones.api.log(i18n.i18n('Parsing.')) tree = self.gobstones.parse(program_text, filename) assert tree # Explode macros self.gobstones.api.log(i18n.i18n('Exploding program macros.')) self.gobstones.explode_macros(tree) # Check semantics, liveness and types self.gobstones.check(tree) self.success() except Exception as exception: self.failure(exception)
def parse_atom(self, tree): if tree.children[0] == 'typeNameTypeCall': 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 not in BasicTypes: msg = i18n.i18n('"%s" is not a basic type') % (tok.value, ) area = common.position.ProgramAreaNear(tok) raise GbsTypeSyntaxException(msg, area) 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 = common.position.ProgramAreaNear(tok) raise GbsTypeSyntaxException(msg, area) return t(*args) 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 init_tags(self): self.reserved = { 'delim': [ '{', '}', '(', ')', ';', ',', ], 'Main': ['Main'], 'keyword': [ 'if', 'else', 'not', 'switch', 'to', 'while', 'foreach', 'in', 'procedure', 'function', 'return', 'div', 'mod', 'Skip', 'from', 'import', ], 'builtin_procedure': [i18n.i18n(name) for name in [ 'THROW_ERROR', 'PutStone', 'TakeStone', 'Move', 'GoToOrigin', 'ClearBoard', ]], 'builtin_function': [i18n.i18n(name) for name in [ 'numStones', 'existStones', 'canMove', 'minBool', 'maxBool', 'minDir', 'maxDir', 'minColor', 'maxColor', 'next', 'prev', 'opposite', ]], 'builtin_constant': [i18n.i18n(name) for name in [ 'True', 'False', 'North', 'South', 'East', 'West', 'Color0', 'Color1', 'Color2', 'Color3', ]], 'type': [i18n.i18n(name) for name in [ 'Color', 'Dir', 'Int', 'Bool', ]], } self.tags = TAGS for tag, (fg, bg) in self.tags.items(): if fg is not None: self.tag_config(tag, foreground=fg) if bg is not None: self.tag_config(tag, background=bg)
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 = common.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 = common.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 compile_foreach_sequence(self, tree, code): "Compile a foreach's sequence." sequence = tree.children[2].children[1:] code.push(('call', i18n.i18n('[]'), 0), near=tree) for element in sequence: self.compile_expression(element, code) code.push(('call', i18n.i18n('_snoc'), 2), near=tree)
def parse_atom(self, tree): if tree.children[0] == 'typeNameTypeCall': 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 not in BasicTypes: msg = i18n.i18n('"%s" is not a basic type') % (tok.value,) area = common.position.ProgramAreaNear(tok) raise GbsTypeSyntaxException(msg, area) 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 = common.position.ProgramAreaNear(tok) raise GbsTypeSyntaxException(msg, area) return t(*args) 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 start_test_case(self, i): if i >= len(self._test_cases): self.log(i18n.i18n('Program execution finished.')) self._state = 'end' return 'END' n_of_m = ' (%s/%s)' % ((i + 1), len(self._test_cases)) self.log( i18n.i18n('Starting test case %s.') % (self._test_cases[i].id(), ) + n_of_m) compiled_code = self._code_dict.compiled_code_for( self._test_cases[i].program_name()) self._test_board = self._bundle.load_board( self._problem, self._test_cases[i].board_name()) try: self._vm = lang.gbs_vm.GbsVmInterpreter( toplevel_filename=self._code_dict._solution_filename) self._vm.init_program(compiled_code, self._test_board) except common.utils.SourceException as exception: self._error_exception = exception self._state = 'failed' return 'FAILED' self._state = 'running' return 'CONTINUE'
def board_change_size(self, *args): if self.tools.DefaultBoardSize == 'random': w, h = 9, 9 else: w, h = self.tools.DefaultBoardSize # ask for size msg = i18n.i18n('Invalid board size') nw = tkinter.simpledialog.askstring( i18n.i18n('Change board size'), i18n.i18n('Width:'), initialvalue='%s' % (w,)) nh = tkinter.simpledialog.askstring( i18n.i18n('Change board size'), i18n.i18n('Height:'), initialvalue='%s' % (h,)) if not common.utils.is_int(nw) or not common.utils.is_int(nh): return self.show_string_error(msg) w, h = int(nw), int(nh) if w == 0 or h == 0 or w > 200 or h > 200: return self.show_string_error(msg) self.tools.DefaultBoardSize = w, h # resize board if not self.viewer: self.open_viewer() self.viewer.randomize() self.viewer.show_board0()
def start(self, filename, program_text, initial_board_string, run_mode): board = tools.board_format.from_string(initial_board_string) if run_mode == Interpreter.RunMode.ONLY_CHECK: options = lang.GobstonesOptions("lax", True, True) else: options = lang.GobstonesOptions() self.gobstones = lang.Gobstones(options, self.api) try: if run_mode == Interpreter.RunMode.FULL: self.success(self.gobstones.run(filename, program_text, board)) else: # Parse gobstones script self.gobstones.api.log(i18n.i18n('Parsing.')) tree = self.gobstones.parse(program_text, filename) assert tree # Explode macros self.gobstones.api.log(i18n.i18n('Exploding program macros.')) self.gobstones.explode_macros(tree) # Check semantics, liveness and types self.gobstones.check(tree) self.success() except Exception as exception: self.failure(exception)
def load(self, board, f): contents = f.read() sizes = list(re.findall('\\GbstnTamanho{([0-9]+)}{([0-9]+)}', contents)) if len(sizes) != 1: raise lang.board.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 = lang.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 lang.board.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 lang.board.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 lang.board.basic.BoardFormatException( i18n.i18n('Malformed tex board')) board.head = y, x board.clear_changelog()
def _infer_func_call(self, tree, nretvals): "Infer types for a function call." fun_name = tree.children[1].value fun_type = self.global_context[fun_name].instantiate() arg_type = self.infer_tuple(tree.children[2]) subtypes = [lang.gbs_type.GbsTypeVar() for i in range(nretvals)] res_type = lang.gbs_type.GbsTupleType(subtypes) expected = lang.gbs_type.GbsFunctionType(arg_type, res_type) # check parameters try: lang.gbs_type.unify(fun_type.paramtype(), expected.paramtype()) except lang.gbs_type.UnificationFailedException as e: area = common.position.ProgramAreaNear(tree) msg = i18n.i18n('function "%s" is receiving: %s\n' + 'But should receive: %s') % (fun_name, expected.paramtype(), fun_type.paramtype()) raise GbsTypeInferenceException(msg, area) # check return value try: lang.gbs_type.unify(fun_type._res, expected._res) except lang.gbs_type.UnificationFailedException as e: area = common.position.ProgramAreaNear(tree) msg = i18n.i18n('function "%s" is called as if it returned: %s\n' + 'But returns: %s') % (fun_name, expected._res, fun_type._res) raise GbsTypeInferenceException(msg, area) tree.type_annotation = expected.parameters() return res_type
def init_tags(self): self.reserved = { 'delim': [ '{', '}', '(', ')', ';', ',', ], 'keyword': [ 'if', 'else', 'not', 'case', 'while', 'switch', 'to', 'match', 'field', 'record', 'is', 'variant', 'type', 'repeat', 'foreach', 'in', 'procedure', 'function', 'return', 'div', 'mod', 'Skip', 'from', 'import', 'program', 'interactive' ], 'builtin_procedure': [i18n.i18n(name) for name in [ 'THROW_ERROR', 'PutStone', 'TakeStone', 'Move', 'GoToOrigin', 'ClearBoard', ]], 'builtin_function': [i18n.i18n(name) for name in [ 'numStones', 'existStones', 'canMove', 'minBool', 'maxBool', 'minDir', 'maxDir', 'minColor', 'maxColor', 'next', 'prev', 'opposite', ]], 'builtin_constant': [i18n.i18n(name) for name in [ 'True', 'False', 'North', 'South', 'East', 'West', 'Color0', 'Color1', 'Color2', 'Color3', ]], 'type': [i18n.i18n(name) for name in [ 'Color', 'Dir', 'Int', 'Bool', ]], } self.tags = TAGS for tag, (fg, bg) in self.tags.items(): if fg is not None: self.tag_config(tag, foreground=fg) if bg is not None: self.tag_config(tag, background=bg)
def check_import(self, tree): mdl_name = tree.children[1].value if not self.module_handler.module_exists(mdl_name): pos = common.position.ProgramAreaNear(tree.children[1]) raise GbsLintException(i18n.i18n('Module %s cannot be found') % (mdl_name,), pos) try: mdl_tree = self.module_handler.parse_tree(mdl_name) except common.utils.SourceException as exception: self.module_handler.reraise(GbsLintException, exception, common.i18n.i18n('Error parsing module %s') % (mdl_name,), common.position.ProgramAreaNear(tree.children[1])) if mdl_name in self.loaded_modules: pos = common.position.ProgramAreaNear(tree.children[1]) raise GbsLintException(i18n.i18n('Recursive modules'), pos) mdl_lint = GbsSemanticChecker(strictness=self.strictness, warn=self.warn, explicit_board=self.explicit_board) try: mdl_lint.check_program(mdl_tree, self.loaded_modules + [mdl_name], is_main_program=False) except common.utils.SourceException as exception: self.module_handler.reraise(GbsLintException, exception, common.i18n.i18n('Error linting module %s') % (mdl_name,), common.position.ProgramAreaNear(tree.children[1])) import_tokens = tree.children[2].children imports = map(lambda imp: imp.value, import_tokens) constructs = tree.children[2].children = mdl_lint.all_defined_routine_or_type_names() if not (len(imports) == 1 and imports[0] == '*'): newcons = [] imported = [] for construct in constructs: if construct.name() in imports: newcons.append(construct) imported.append(construct.name()) if isinstance(construct, lang.gbs_constructs.UserType): newcons.extend(mdl_lint.field_getters_for_type(construct.name())) constructs = newcons invalid_imports = set(imports).difference(set(imported)) if len(invalid_imports) > 0: import_index = imports.index(invalid_imports[0]) mdl_lint.symbol_table._error_not_defined(import_tokens[import_index], imports[import_index], 'type or callable') for construct in constructs: if isinstance(construct, lang.gbs_constructs.BuiltinFieldGetter): if not construct.name() in self.imported_rtns: self.symbol_table.add(construct, area=None) self.imported_rtns[construct.name()] = True else: if construct.name() in self.imported_rtns: pos = common.position.ProgramAreaNear(construct.identifier()) raise GbsLintException(i18n.i18n('%s %%s was already imported' % (construct.type(),)) % (construct.name(),), pos) else: self.symbol_table.add(construct, area=common.position.ProgramAreaNear(construct.identifier())) self.imported_rtns[construct.name()] = True
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 __init__(self, tools, parent_gui=None, font=gui.config.DefaultFont, *args, **kwargs): tkinter.Tk.__init__(self, *args, **kwargs) self.tools = tools self.parent_gui = parent_gui self._font = font bframe = tkinter.Frame(self) ti = i18n.i18n('Initial board') tf = i18n.i18n('Final board') self.button0 = tkinter.Button(bframe, text=ti, command=self.show_board0) self.button1 = tkinter.Button(bframe, text=tf, command=self.show_board1) self.button0.pack(side=tkinter.LEFT) self.button1.pack(side=tkinter.LEFT) self.bind_all('<KeyPress>', self.keypress) self.bind_all('<z>', self.board_zoom_out) self.bind_all('<x>', self.board_zoom_in) self.bind_all('<KeyPress-Up>', lambda ev: self.keypress_cursor(self.tools.builtins.NORTH, ev)) self.bind_all('<KeyPress-Down>', lambda ev: self.keypress_cursor(self.tools.builtins.SOUTH, ev)) self.bind_all('<KeyPress-Left>', lambda ev: self.keypress_cursor(self.tools.builtins.WEST, ev)) self.bind_all('<KeyPress-Right>', lambda ev: self.keypress_cursor(self.tools.builtins.EAST, ev)) self.bind_all('<Home>', lambda ev: self.grandmove('home')) self.bind_all('<End>', lambda ev: self.grandmove('end')) self.bind_all('<Prior>', lambda ev: self.grandmove('up')) self.bind_all('<Next>', lambda ev: self.grandmove('down')) bframe.pack(side=tkinter.TOP, fill=tkinter.X) self.board0 = self.tools.Board((1, 1)) self.board0.randomize_full() self.board1 = self.tools.Board((1, 1)) self.reset_board1() self._build_scrolled_board_frame() self.err_frame = None self.show_board0() self.visible_board = None self.filename = None if self.parent_gui: self.bind_all('<Control-e>', self.parent_gui.board_empty) self.bind_all('<Control-i>', lambda *args: self.parent_gui.board_random_full()) self.bind_all('<Control-r>', lambda *args: self.parent_gui.board_random_contents()) self.bind_all('<Control-t>', self.parent_gui.board_change_size) self.bind_all('<Control-b>', lambda *args: self.parent_gui.board_load()) self.bind_all('<Control-g>', lambda *args: self.parent_gui.board_save()) self.bind_all('<Control-n>', self.parent_gui.file_new) self.bind_all('<Control-o>', self.parent_gui.file_open) self.bind_all('<Control-s>', self.parent_gui.file_save) self.bind_all('<F5>', self.parent_gui.gobstones_start_run) self.bind_all('<F10>', self.parent_gui.gobstones_check)
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 += common.utils.indent( bnf_rule_to_str(self._parse_table[(nonterminal, terminal)])) self.warn(ParserException(msg, area))
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 += common.utils.indent(bnf_rule_to_str( self._parse_table[(nonterminal, terminal)])) self.warn(ParserException(msg, area))
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 _file_close(self): if self.editor.text_has_changed(): ans = tkinter.messagebox.askyesnocancel( i18n.i18n('File not saved'), i18n.i18n('File has not been saved.\nSave it now?')) if ans is None: return False if ans == True: if not self.file_save(): return False self.editor.new_file() return True
def draw_stone(self, x0, y0, x1, y1, col, count): if count == 0: return sm = (x1 - x0) // 8 fill = i18n.i18n(Colors['stone_fill%i' % (col,)]) outline = i18n.i18n(Colors['stone_border%i' % (col,)]) self.create_oval(x0 + sm, y0 + sm, x1 - sm, y1 - sm, outline=outline, fill=fill, width=1) self.create_text((x0 + x1) // 2, (y0 + y1) // 2, font=self._font, text=str(count), justify=tkinter.CENTER)
def _init_filetypes(self): self.filetypes = { 'gbs': [ (i18n.i18n('Gobstones source'), '*.gbs', 'TEXT'), (i18n.i18n('All files'), '*'), ], } self.filetypes['board_load'] = [ (i18n.i18n('Gobstones board'), '*.gbb', 'TEXT'), (i18n.i18n('Gobstones board (old format)'), '*.gbt', 'TEXT'), (i18n.i18n('TeX/LaTeX file'), '*.tex', 'TEXT'), ] self.filetypes['board_save'] = self.filetypes['board_load'][:] self.filetypes['board_save'].append( (i18n.i18n('HTML file'), '*.html', 'TEXT') ) self.filetypes['board_save'].append( (i18n.i18n('FIG image file'), '*.fig', 'TEXT') ) self.filetypes['board_load'].append( (i18n.i18n('All files'), '*'), ) self.filetypes['board_save'].append( (i18n.i18n('All files'), '*'), )
def board_move(global_state, direction): """Move the head.""" if poly_typeof(direction) != 'Dir': msg = i18n.i18n('The argument to Move should be a direction') raise GbsRuntimeException(msg, global_state.area()) if global_state.board.can_move(direction): global_state.board.move(direction) else: msg = global_state.backtrace( i18n.i18n('Cannot move to %s') % (direction,)) raise GbsRuntimeException(msg, global_state.area())
def board_take_stone(global_state, color): """Take a stone from the board.""" if poly_typeof(color) != 'Color': msg = i18n.i18n('The argument to TakeStone should be a color') raise GbsRuntimeException(msg, global_state.area()) if global_state.board.num_stones(color) > 0: global_state.board.take_stone(color) else: msg = global_state.backtrace( i18n.i18n('Cannot take stones of color %s') % (color,)) raise GbsRuntimeException(msg, global_state.area())
def board_take_stone(global_state, color): """Take a stone from the board.""" if poly_typeof(color) != 'Color': msg = i18n.i18n('The argument to TakeStone should be a color') raise GbsRuntimeException(msg, global_state.area()) if global_state.board.num_stones(color) > 0: global_state.board.take_stone(color) else: msg = global_state.backtrace( i18n.i18n('Cannot take stones of color %s') % (color, )) raise GbsRuntimeException(msg, global_state.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 = lang.gbs_type.GbsTupleType(param_types) if prfn == 'procedure': def_type = lang.gbs_type.GbsProcedureType(param_types) elif prfn == 'function': return_types = self._return_type(prfn, name, params, body) def_type = lang.gbs_type.GbsFunctionType(param_types, return_types) elif prfn == 'entrypoint' and (name.value == 'program' or name.value == 'interactive'): def_type = lang.gbs_type.GbsEntryPointType() else: assert False expected = self.global_context[name.value].instantiate() try: lang.gbs_type.unify(expected, def_type) if prfn == 'function': #[TODO] Check freevars = def_type.freevars() if len(freevars) > 0: def_type = lang.gbs_type.GbsForallType(freevars, def_type) self.global_context[name.value] = def_type tree.type_annot = def_type except lang.gbs_type.UnificationFailedException as e: area = common.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 = common.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 = common.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 list_binary_operation(global_state, lst1, lst2, f): """Wrapper for binary list operations to ensure list types""" if poly_typeof(lst1) == poly_typeof(lst2) and poly_typeof(lst1) == 'List' and list_inner_type_eq(lst1, lst2): return f(lst1, lst2) else: if poly_typeof(lst1) != 'List': msg = global_state.backtrace(i18n.i18n('%s was expected') % (i18n.i18n('list type value'),)) raise GbsRuntimeException(msg, global_state.area()) else: msg = global_state.backtrace(i18n.i18n('Concatenation between lists with different inner type.')) raise GbsRuntimeException(msg, global_state.area())
def compile_foreach_range(self, tree, code): "Compile a foreach's range." _, range_first, range_last, range_second = tree.children[2].children self.compile_expression(range_first, code) self.compile_expression(range_last, code) if not range_second is None: self.compile_expression(range_second, code) else: self.compile_expression(range_first, code) code.push(('call', i18n.i18n('next'), 1), near=tree) code.push(('call', i18n.i18n('_range'), 3), near=tree)
def board_move(global_state, direction): """Move the head.""" if poly_typeof(direction) != 'Dir': msg = i18n.i18n('The argument to Move should be a direction') raise GbsRuntimeException(msg, global_state.area()) if global_state.board.can_move(direction): global_state.board.move(direction) else: msg = global_state.backtrace( i18n.i18n('Cannot move to %s') % (direction, )) raise GbsRuntimeException(msg, global_state.area())
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(lang.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 = common.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 = common.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(lang.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 = common.position.ProgramAreaNear(tree) raise GbsLintException(msg, area) elif var.type() == 'parameter': msg = i18n.i18n('Cannot modify "%s": parameter is immutable') % (varName,) area = common.position.ProgramAreaNear(tree) raise GbsLintException(msg, area)
def _put_from_description(self, cell, description): coli = 0 for cn in lang.gbs_builtins.COLOR_NAMES: if description[-1].lower() == cn[0].lower(): count = description[:-1] for l in count: if l not in '0123456789': raise lang.board.basic.BoardFormatException(i18n.i18n('Malformed board')) cell.put(coli, int(count)) return coli += 1 raise lang.board.basic.BoardFormatException(i18n.i18n('Malformed board'))
def force_file_save(self, *args): if self.editor.has_filename(): self.editor.save_file(self.editor.filename()) return True else: ans = tkinter.messagebox.askyesno( i18n.i18n('Source must be saved'), i18n.i18n('Source must be saved.\nOk to save?')) if ans == True: return self.file_save_as() else: return False
def run_filename(fn, **options): if not os.path.exists(fn): report_error(i18n.i18n('Error'), i18n.i18n('File %s does not exist') % (fn, )) return False lfn = fn.lower() if lfn.endswith('.gbo'): return run_object_filename(fn, **options) elif lang.board.formats.is_board_filename(fn): return run_board_filename(fn, **options) else: return run_gbs_filename(fn, **options)
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) # Optimize program if self.options.optimize: self.api.log(i18n.i18n('Optimizing.')) #[TODO] i18n lang.gbs_optimizer.optimize(tree) # Compile program self.api.log(i18n.i18n('Compiling.')) gbs_run.compiled_program = self.compile_program(tree) return gbs_run
def _error_conflictive_definition(self, tree, name, as_type, val): if val.name() == name: area = common.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 = common.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 _result(self, tit, out, board, head_pos, keyvals): if board is not None: out.write(' <h3>%s</h3>\n' % (tit,)) out.write(html_board(board, draw_head=self._options['check_head'])) if self._options['check_result']: out.write(' <h3>%s</h3>\n' % (i18n.i18n('Returned variables'),)) if len(keyvals) == 0: out.write(' <tt><%s></tt>\n' % (i18n.i18n('No returned variables'),)) else: out.write(' <div class="returned_vars">\n') for k, v in keyvals: out.write('<p><tt>%s -> %s</tt></p>\n' % (k, v)) out.write(' </div>\n')
def parse_error(self, nonterminal, previous_token, token): "Raises a GbstonesParserException describing a parse error." area = common.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) lang.bnf_parser.Parser.parse_error(self, nonterminal, previous_token, token)
def _tabmenu(self, out): out.write('<p>\n') out.write( ' <input type="submit" class="btn" id="link_test_case" onclick="show(\'test_case\')" value="%s">\n' % (i18n.i18n('Test case'), )) if self._options['provide_expected_result']: out.write( ' <input type="submit" class="btn" id="link_expected_result" onclick="show(\'expected_result\')" value="%s">\n' % (i18n.i18n('Expected result'), )) out.write( ' <input type="submit" class="btn" id="link_obtained_result" onclick="show(\'obtained_result\')" value="%s">\n' % (i18n.i18n('Obtained result'), )) out.write('</p>\n')
def check_import(self, tree): mdl_name = tree.children[1].value if not self.module_handler.module_exists(mdl_name): pos = common.position.ProgramAreaNear(tree.children[1]) raise GbsLintException(i18n.i18n('Module %s cannot be found') % (mdl_name,), pos) try: mdl_tree = self.module_handler.parse_tree(mdl_name) except common.utils.SourceException as exception: self.module_handler.reraise(GbsLintException, exception, common.i18n.i18n('Error parsing module %s') % (mdl_name,), common.position.ProgramAreaNear(tree.children[1])) if mdl_name in self.loaded_modules: pos = common.position.ProgramAreaNear(tree.children[1]) raise GbsLintException(i18n.i18n('Recursive modules'), pos) mdl_lint = GbsSemanticChecker(strictness=self.strictness, warn=self.warn) try: mdl_lint.check_program(mdl_tree, self.loaded_modules + [mdl_name], is_main_program=False) except common.utils.SourceException as exception: self.module_handler.reraise(GbsLintException, exception, common.i18n.i18n('Error linting module %s') % (mdl_name,), common.position.ProgramAreaNear(tree.children[1])) rtns = tree.children[2].children if len(rtns) == 1 and rtns[0].value == '*': rtns = tree.children[2].children = mdl_lint.all_defined_routine_or_type_names() for rtn in rtns: if rtn.type == 'lowerid': construct_type = 'function' else: construct_type = 'procedure' if mdl_lint.symbol_table.is_defined_as(rtn, rtn.value, 'callable', construct_type): construct = mdl_lint.symbol_table.get('callable', rtn.value, None) elif mdl_lint.symbol_table.is_defined_as(rtn, rtn.value, 'atomic', 'type'): construct_type = 'type' rtn.is_type_annotation = True construct = mdl_lint.symbol_table.get('atomic', rtn.value, None) else: mdl_lint.symbol_table._error_not_defined(rtn, rtn.value, 'type or callable') if rtn.value in self.imported_rtns: pos = common.position.ProgramAreaNear(rtn) raise GbsLintException(i18n.i18n('%s %%s was already imported' % (construct_type,)) % (rtn.value,), pos) self.imported_rtns[rtn.value] = True self.symbol_table.add(construct, area=common.position.ProgramAreaNear(rtn))
def _result(self, tit, out, board, head_pos, keyvals): if board is not None: out.write(' <h3>%s</h3>\n' % (tit, )) out.write(html_board(board, draw_head=self._options['check_head'])) if self._options['check_result']: out.write(' <h3>%s</h3>\n' % (i18n.i18n('Returned variables'), )) if len(keyvals) == 0: out.write(' <tt><%s></tt>\n' % (i18n.i18n('No returned variables'), )) else: out.write(' <div class="returned_vars">\n') for k, v in keyvals: out.write('<p><tt>%s -> %s</tt></p>\n' % (k, v)) out.write(' </div>\n')
def run_runnable(runnable, **options): try: board = lang.gbs_board.Board((1, 1)) if options['from']: inb = options['from'] if not os.path.exists(inb): report_error(i18n.i18n('Error'), i18n.i18n('File %s does not exist') % (inb, )) return False fmt = options['from'].split('.')[-1] fmt = fmt.lower() if fmt not in lang.board.formats.AvailableFormats: fmt = lang.board.formats.DefaultFormat f = open(inb, 'r') board.load(f, fmt=fmt) f.close() else: if options['size']: board.clone_from(lang.gbs_board.Board(options['size'])) board.randomize_contents() else: board.randomize_full() initial_board = board.clone() result = runnable.run(board) if options['to']: f = open(options['to'], 'w') fmt = options['to'].split('.')[-1] fmt = fmt.lower() if fmt not in lang.board.formats.AvailableFormats: fmt = lang.board.formats.DefaultFormat board.dump(f, fmt=fmt, style=style(options)) f.close() if options['print-input']: print(initial_board) if options['print-board']: print(board) if options['print-retvals']: for var, val in result: print('%s -> %s' % (var, val)) if not options['print-board']: print('OK') except common.utils.SourceException as exception: report_program_error(exception.error_type(), exception.msg, exception.area) return True
def _input_board(self, out): out.write(' <div id="test_case" class="info_frame" style="background:#c0c0c0">\n') out.write(' <h3>%s</h3>\n' % (i18n.i18n('Initial board'),)) input_board = self._initial_board out.write(html_board(input_board)) if self._source_code: out.write(' <h3>%s</h3>\n' % (i18n.i18n('Source code'),)) out.write('<pre>') out.write(html_escape(pprint(self._source_code, self._test_case.run_name()))) out.write('</pre>') out.write(' </div>\n')
def compile(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) # Check semantics, liveness and types self.check(tree) # Compile program self.api.log(i18n.i18n('Compiling.')) compiled_program = self.compile_program(tree) return GobstonesRun().initialize(tree, compiled_program)
def build_special_key_constants(self): return [ self.build_key_constant(i18n.i18n("K_ARROW_LEFT"), GobstonesKeys.ARROW_LEFT), self.build_key_constant(i18n.i18n("K_ARROW_UP"), GobstonesKeys.ARROW_UP), self.build_key_constant(i18n.i18n("K_ARROW_RIGHT"), GobstonesKeys.ARROW_RIGHT), self.build_key_constant(i18n.i18n("K_ARROW_DOWN"), GobstonesKeys.ARROW_DOWN), self.build_key_constant('K_CTRL_D', 4), self.build_key_constant('K_ENTER', 13), self.build_key_constant('K_SPACE', 32), self.build_key_constant('K_DELETE', 46), self.build_key_constant('K_BACKSPACE', 8), self.build_key_constant('K_TAB', 9), self.build_key_constant('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 = common.position.ProgramAreaNear(tree) raise GbsUnusedVarException(msg, area)
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(lang.gbs_constructs.UserIndex(varName, tree)) elif var.type() == 'variable': msg = i18n.i18n( 'Index of a foreach cannot be a variable: "%s"') % (varName, ) area = common.position.ProgramAreaNear(tree) raise GbsLintException(msg, area) elif var.type() == 'parameter': msg = i18n.i18n( 'Index of a foreach cannot be a parameter: "%s"') % (varName, ) area = common.position.ProgramAreaNear(tree) raise GbsLintException(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' + common.utils.indent('\n'.join(follow)) raise ParserException(msg, common.position.ProgramAreaNear(token))
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 = lang.gbs_type.GbsTupleType(param_types) if prfn == 'procedure': def_type = lang.gbs_type.GbsProcedureType(param_types) elif prfn == 'function': return_types = self._return_type(prfn, name, params, body) def_type = lang.gbs_type.GbsFunctionType(param_types, return_types) elif prfn == 'entrypoint' and (name.value == 'program' or name.value == 'interactive'): def_type = lang.gbs_type.GbsEntryPointType() else: assert False expected = self.global_context[name.value].instantiate() try: lang.gbs_type.unify(expected, def_type) if prfn == 'function': #[TODO] Check freevars = def_type.freevars() if len(freevars) > 0: def_type = lang.gbs_type.GbsForallType(freevars, def_type) self.global_context[name.value] = def_type tree.type_annot = def_type except lang.gbs_type.UnificationFailedException as e: area = common.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 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 = common.position.ProgramAreaNear(tree) raise GbsUnusedVarException(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_binary_op, '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 = common.position.ProgramAreaNear(tree) raise GbsLivenessException(msg, area) return tree.live_gen