Python internally compiles to a bytecode for a stack-based virtual machine. If you import the module `dis` and execute `dis.dis` on a function, you can see this bytecode.
Like most bytecode VMs, there are jump instructions for compiling for and while loops to. For example,
a, b = 0, 1
for i in range(n):
a, b = b, a + b
2 0 LOAD_CONST 3 ((0, 1))
3 UNPACK_SEQUENCE 2
6 STORE_FAST 1 (a)
9 STORE_FAST 2 (b)
3 12 SETUP_LOOP 37 (to 52)
15 LOAD_GLOBAL 0 (range)
18 LOAD_FAST 0 (n)
21 CALL_FUNCTION 1
>> 25 FOR_ITER 23 (to 51)
28 STORE_FAST 3 (i)
4 31 LOAD_FAST 2 (b)
34 LOAD_FAST 1 (a)
37 LOAD_FAST 2 (b)
42 STORE_FAST 1 (a)
45 STORE_FAST 2 (b)
48 JUMP_ABSOLUTE 25
>> 51 POP_BLOCK
5 >> 52 LOAD_FAST 1 (a)
The rest is a simple job of identifying the syntax (`goto .x` is really `goto.x`, an attribute access, which is simple to identify as the `LOAD_ATTR` instruction) and inserting the proper jumps. So in fact this is a pure-python modification, which works solely by changing how Python compiles to bytecode.
Jokes aside, Kay Schluehr did a package called generator_tools:
I used it to do iterators serialisation in Python, which is quite an ambitious task (BTW, it should be supported by the language really).
This is the recipe for you if you are sick of the slow speed of the existing goto module http://entrian.com/goto/. The goto in this recipe is about 60x faster
int test_check(char *file_name)
35 FILE *input = NULL;
36 char *block = NULL;
38 block = malloc(100);
39 check_mem(block); // should work
41 input = fopen(file_name,"r");
42 check(input, "Failed to open %s.", file_name);
46 return 0;
49 if(block) free(block);
50 if(input) fclose(input);
51 return -1;
When was the last time someone proved a program correct?
As an addendum GOTO is still bad because it is much harder to parse (as a human reading the code) than using equivalent branching control statements. That was the whole point of Goto considered harmful, it's not mathematically needed so it's not syntactically needed either.
1) Do not take the presented code as evidence that arbitrarily new syntax can be created. Any code that raises a SyntaxError will still be invalid.
2) I believe there is a legitimate reason to use bytecode hackery -- I've come across it many times: the slowness of Python.
For example, let's say I have three functions as follows.
return a + 1
return 2a + 1
It's clear that f(g(x)) == h(x) for all values of x. But h will run faster (marginally in this case, but try to imagine more complicated cases) because the Python interpreter will never make such an optimization. Function calls will be made, frames generated, etc. -- and that's where bytecode hackery comes in! Imagine pasting f and g together so that I never have to write h but still get the benefit of speed.
I do recognize that in many cases, it may be preferable to just use a more low-level language to optimize away such functions, but I always like to envision a pure Python solution first.
I thought about this and wrote a patch for CPython that it also stores the original AST of any compiled function in the function object.
Some discussion about this:
The other option is to wrap the thing decorated in a doc string
put some haskell or DSL stuff in here