Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for closures, loops, classes in REPL #4

Open
scottdavis opened this issue Dec 10, 2009 · 21 comments
Open

Add support for closures, loops, classes in REPL #4

scottdavis opened this issue Dec 10, 2009 · 21 comments
Labels

Comments

@scottdavis
Copy link

This was bugging me for awhile and i hacked away for about 2.5 hours trying to figure out a work about but
example:

> $foo = function() {return 'bar';}
> 
Uncaught exception with command:
Fatal error executing php: PHP Fatal error:  Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed' in /private/var/folders/oQ/oQhij0hDFVOxzm9dMI9EC++++TI/-Tmp-/iphp.command.U3N9Oo:18
Stack trace:
#0 /private/var/folders/oQ/oQhij0hDFVOxzm9dMI9EC++++TI/-Tmp-/iphp.command.U3N9Oo(18): serialize(Array)
#1 {main}
  thrown in /private/var/folders/oQ/oQhij0hDFVOxzm9dMI9EC++++TI/-Tmp-/iphp.command.U3N9Oo on line 18

Exception: Serialization of 'Closure' is not allowed in /private/var/folders/oQ/oQhij0hDFVOxzm9dMI9EC++++TI/-Tmp-/iphp.command.U3N9Oo on line 18

Call Stack:
    0.0004     635040   1. {main}() /private/var/folders/oQ/oQhij0hDFVOxzm9dMI9EC++++TI/-Tmp-/iphp.command.U3N9Oo:0
    0.0009     637576   2. serialize() /private/var/folders/oQ/oQhij0hDFVOxzm9dMI9EC++++TI/-Tmp-/iphp.command.U3N9Oo:18

Same goes for defining functions and classes
function:

> function foo() {return 'bar';}
> 
Uncaught exception with command:
Fatal error executing php: PHP Parse error:  syntax error, unexpected T_STRING, expecting '(' in /private/var/folders/oQ/oQhij0hDFVOxzm9dMI9EC++++TI/-Tmp-/iphp.command.8CUHcL on line 12

Parse error: syntax error, unexpected T_STRING, expecting '(' in /private/var/folders/oQ/oQhij0hDFVOxzm9dMI9EC++++TI/-Tmp-/iphp.command.8CUHcL on line 12
> 

Classes:

> class Foo {}
> 
Uncaught exception with command:
Fatal error executing php: PHP Parse error:  syntax error, unexpected T_CLASS in /private/var/folders/oQ/oQhij0hDFVOxzm9dMI9EC++++TI/-Tmp-/iphp.command.Pk4qgL on line 12

Parse error: syntax error, unexpected T_CLASS in /private/var/folders/oQ/oQhij0hDFVOxzm9dMI9EC++++TI/-Tmp-/iphp.command.Pk4qgL on line 12
> 

While i had a work around working the storing of $_ and $__out are not possible when you create a a special case even "foreach" will explode using serialization

foreach(range(0,10) as $i) { echo $i; }
> 
Uncaught exception with command:
Fatal error executing php: PHP Parse error:  syntax error, unexpected T_FOREACH in /private/var/folders/oQ/oQhij0hDFVOxzm9dMI9EC++++TI/-Tmp-/iphp.command.mXsYfJ on line 12

Parse error: syntax error, unexpected T_FOREACH in /private/var/folders/oQ/oQhij0hDFVOxzm9dMI9EC++++TI/-Tmp-/iphp.command.mXsYfJ on line 12
> 

Solution is avoid serialization and store the code input unserialized in a file and keep appending to it and re-executing, As for returning output some string parsing may be in order to find variables and var_dump-ing them may be in order or just rely or just print tokenize the last returnable line;

edit: fixed typo's my brain is fried

@apinstein
Copy link
Owner

wow interesting problem, I hadn't even contemplated trying to do this type of thing. but clearly it's cool!

Did you get to a solution? I am too tired to think about it myself atm :)

@apinstein
Copy link
Owner

maybe we need some special multi-line mode?

@scottdavis
Copy link
Author

I had it working sort of kind of but them that way would break when it was serialized so multi-line mode = no serialization of anything

The real problem isn't getting a multi-line mode working its this block of code

ob_start();
\$_ = {$command};
\$__out = ob_get_contents();
ob_end_clean();

Sticking "class Foo {}" into the $_ = class Foo {} throws a syntax error

@apinstein
Copy link
Owner

Wow yeah so irb lets you write any ruby. no wonder they have "reload"!

I think we could accomplish that with some kind of "eval vs define" mode.

Currently we have eval mode, but we could have certain keywords trigger "define" mode, like "class, interface, function, etc".

Then store that data separately in a single "multiline_require" file that would be included just before the $_ = {$command}

Does that sound promising?

@apinstein
Copy link
Owner

Actually maybe this is an ideal situation to use the built-in php tokenizer:

http://us2.php.net/manual/en/function.token-get-all.php

Pre-parse the entered line and see what it looks like. No idea how it deals with syntax errors.

@scottdavis
Copy link
Author

well you run php_check_syntax($file) then you tokenize it
ill prototype something tomorrow and post it in a branch

@scottdavis
Copy link
Author

and the way i was doing it was running this huge regex i made "/^(class|function|interface|foreach|etc)/"
your above solution should solve the problem for classes but foreach and inline block operators will need even more special care

@apinstein
Copy link
Owner

php_check_syntax is deprecated/obselete.

based on the way irb looks like it works, I think we just have to keep track of what's being entered. When you hit ENTER look at the line for quotes, foreach, etc and maintain state... then keep a single file with all of these commands and keep appending them. they'd have to be run each time in the repl exec tho which could get slow for certain things (and certianly not be idempotent either).

@scottdavis
Copy link
Author

the way i had it working for classes was it detected the { operator and } operator and tracked nested operators so making

class Foo {
 public function __construct() {

 }
}

Had a nested of index of 2 and stored each entered line in and array until the last } was captured setting the nested counter to zero then i was injecting them into the doCommand() as a array imploded on "\n"

@apinstein
Copy link
Owner

it's def a start, but I think too primitive. it'd be ideal to follow the PHP parsing rules by using token_get_all(), then we won't have to educate people on how to hack iphp to enable multi-line stuff...

@scottdavis
Copy link
Author

started working on a tokenizer class
http://github.com/jetviper21/iphp/tree/b282e9ccc3d17ca333db0e807d980899f9727c0e

@apinstein
Copy link
Owner

cool! looks promising.

I think it might be wiser to have more than just a "multi-line" boolean; rather use a state stack which effects what action happens on RETURN.

For instance, "" will just let the NL through since NL is a valid char for quoted strings. But certain keywords or blocks will enter multi-line mode, and who knows if we'll need different ones.

We can just maintain an internal stack of "inputMode" with options like MODE_QUOTED_STRING, MODE_BLOCK, etc as needed, and then each mode can look for its "close" tag.

Make sense?

@scottdavis
Copy link
Author

well i created the boolean to run a test from inside doCommand if that passes i was going to write a buffering class (that implements the state stack) that can handle the multi line input and store it until its valid executable syntax i see no need ot crud up the main class with this

@apinstein
Copy link
Owner

Yeah i like the idea of a buffering class... could be used to do multi-line php input in any project (although not sure how big of a need that is...)

@scottdavis
Copy link
Author

Few things as im hacking through this im working on the doCommand function and was wondering why eval will not work for the main code execution so we don't need to use tempfiles?

@apinstein
Copy link
Owner

that's how it used to work but there is a big problem with that. The "host" of eval() dies if there's a fatal error.

Thus if you did something like $a->foo() you'd get a FATAL error that would kill the shell.

IMO the "fatal-safety" of iphp is the killer feature it has; I'd never seen it done anywhere else before and this problem severely limited the utility of the shell for me since it would die after you'd built up state because of a simple typo.

@scottdavis
Copy link
Author

totally understand i didn't know you couldn't try catch an eval

@scottdavis
Copy link
Author

just finished moving some stuff out and writing some tests going to start working on test cases for the main class so i can build out a multi line function without breaking everything

@apinstein
Copy link
Owner

i have made a bunch of mods; please rebase your feature branch on my master, thanks!

@scottdavis
Copy link
Author

i have already merged in most of bermi's changes ill get around to pulling yours down tomorrow

@apinstein
Copy link
Owner

Scott not sure if you're working on this any more, but I did hook up iphp to token_get_all() tonight and managed to get iphp working gracefully when the "command" doesn't return data.

I would be very interested in your multiline stuff now...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants