""" Turtle DSL ========== Implements a LOGO-like toy language for Python’s turtle, with interpreter. """ try: input = raw_input # For Python2 compatibility except NameError: pass import turtle from lark import Lark turtle_grammar = """ start: instruction+ instruction: MOVEMENT NUMBER -> movement | "c" COLOR [COLOR] -> change_color | "fill" code_block -> fill | "repeat" NUMBER code_block -> repeat code_block: "{" instruction+ "}" MOVEMENT: "f"|"b"|"l"|"r" COLOR: LETTER+ %import common.LETTER %import common.INT -> NUMBER %import common.WS %ignore WS """ parser = Lark(turtle_grammar) def run_instruction(t): if t.data == 'change_color': turtle.color(*t.children) # We just pass the color names as-is elif t.data == 'movement': name, number = t.children { 'f': turtle.fd, 'b': turtle.bk, 'l': turtle.lt, 'r': turtle.rt, }[name](int(number)) elif t.data == 'repeat': count, block = t.children for i in range(int(count)): run_instruction(block) elif t.data == 'fill': turtle.begin_fill() run_instruction(t.children[0]) turtle.end_fill() elif t.data == 'code_block': for cmd in t.children: run_instruction(cmd) else: raise SyntaxError('Unknown instruction: %s' % t.data) def run_turtle(program): parse_tree = parser.parse(program) for inst in parse_tree.children: run_instruction(inst) def main(): while True: code = input('> ') try: run_turtle(code) except Exception as e: print(e) def test(): text = """ c red yellow fill { repeat 36 { f200 l170 }} """ run_turtle(text) if __name__ == '__main__': # test() main()