richpl / PyBasic

Simple interactive BASIC interpreter written in Python
GNU General Public License v3.0
170 stars 46 forks source link

Modularisation and Command Hooks (Question) #31

Closed JiFish closed 3 years ago

JiFish commented 3 years ago

With all the tasty fixes incoming, I am seriously regretting having to fork the project for Artemis. Pulling from upstream is a bit of a pain currently. Would you be interested in a PR with the following changes?

a) Ability to import PyBasic as a module b) Ability to add or override commands externally from PyBasic.

Together this would allow me to isolate my modifications from PyBasic and more easily pull in fixes.

I wouldn't have time to look at this right away, but if you are interested, I will add this to my to-do list.

brickbots commented 3 years ago

Hi @JiFish ! Your Artemis project is pretty sweet. I saw it linked from one of the closed issues / PR's you submitted and I'm a big fan.

I agree that a bit more separation of responsibility in the code could be really nice for reuse among projects. I've been working with a version that has everything but interpreter.py in a pybasic module, and have been debating moving some items like 'list' into interpreter (but still leaving the line serialization in the program class). This should make the actual BASIC engine pretty isolated and all the UI responsibilities (where there is likely much custom stuff) lives in interpreter or some custom version of it.

Along with this I'd like to abstract all the print/input stuff in some way. I'm thinking some simple class that represents a terminal and gets passed into program when execute is called. Thoughts? In the version I have running on the handheld hardware I just monkey patched program, but it ruins the ability to use upstream changes so I'm keen to get the core BASIC interpreter back in line with the mother PyBasic repo.

I'm super curious what you are thinking of for adding commands externally? I've thought about trying this by subclassing basictoken and basicparser and trying to work out some solid method for looking up function calls dynamically. There is a lot of this pattern of code in basicparser.py:

        elif category == Token.ATN:
            try:
                return math.atan(value)

            except ValueError:
                raise ValueError("Invalid value supplied to ATN in line " +
                                 str(self.__line_number))

        elif category == Token.COS:
            try:
                return math.cos(value)

            except ValueError:
                raise ValueError("Invalid value supplied to COS in line " +
                                 str(self.__line_number))

And I think it might be able to be replaced by a dictionary of token categories mapped to functions. This would make expanding the dialect by adding new keywords much easier.

I opened issue #25 with a laundry list of possible changes to see what the original author thought. This sort of modularization is something I'm keen on as well.

JiFish commented 3 years ago

Hi @brickbots, I saw your pull requests and was super impressed. I somehow managed to miss #25 - it seems you are already several steps ahead of my thinking.

I'll go ahead and reply to your questions in that issue, so we can keep everything together.