Ruby 2.0, 65 76 164 characters
eval r="gets p;$<.pos=0;`ruby -c 2>&0`;p$?==0&&$_!='eval r=%p'%r"
This uses Ruby's built-in syntax checker (ruby -c
) to check the input's syntax, which means the code won't be evaluated.
Basic usage example:
ruby syntax.rb <<< foo
true
ruby syntax.rb <<< "'"
false
ruby syntax.rb < synxtax.rb # assumes the file was saved without trailing newline
false
Explanation
This solution is (was) based on the standard Ruby quine:
q="q=%p;puts q%%q";puts q%q
%p
is the format specifier for arg.inspect
, which can be compared to uneval
: when eval
ing the string returned by arg.inspect
, you (usually) get the original value again. Thus, when formatting the q
string with itself as argument, the %p
inside the string will be replaced with the quoted string itself (i.e. we get something like "q=\"q=%p;puts q%%q\";puts q%q"
).
Generalizing this type of quine leads to something like the following:
prelude;q="prelude;q=%p;postlude";postlude
This approach has one huge drawback though (at least in code-golf): All code needs to be duplicated. Luckily, eval
can be used to get around this:
eval r="some code;'eval r=%p'%r"
What happens here is that the code passed to eval is stored inside r
before eval
is called. As a result, the full source code of the eval
statement can be obtained with 'eval r=%p'%r
. If we do this inside the eval
d code and ensure that the top level of our consists only of the one eval
statement, that expression actually gives us the full source code of our program, since any additional code passed to eval
is already stored inside r
.
Side note: This approach actually allows us to write a Ruby quine in 26 characters: eval r="puts'eval r=%p'%r"
Now, in this solution the additional code executed inside eval
consists of four statements:
gets p
First, we read all input from STDIN and implicitly save it into $_
.
$<.pos=0
Then, we rewind STDIN so the input is available again for the subprocess we start in the next step.
`ruby -c 2>&0`
This starts Ruby in its built-in syntax checking mode, reading the source code from stdin. If the syntax of the supplied script (filename or stdin) is ok, it prints Syntax OK
to its stdout (which is captured by the parent process), but in case of a syntax error, a description of the error is printed to stderr - which would be visible, so we redirect that into nirvana (2>&0
) instead.
p$?==0&&$_!='eval r=%p'%r
Afterwards, we check the subprocess's exit code $?
, which is 0 if the syntax was ok. Lastly, the input we read earlier ($_
) is compared against our own source code (which, as I described earlier, can be obtained with 'eval r=%p'%r
).
Edit: Saved 14 characters thanks to @histocrat!
try:exec(raw_input())...
allowed? \$\endgroup\$