Giter Club home page Giter Club logo

rfunge's Introduction

rfunge โ€“ rustiest of funges

RFunge is a standards-compliant Funge-98 interpreter written in Rust.

It currently supports Unefunge and Befunge in 32-bit and 64-bit modes, and should support Trefunge (and possibly higher dimensions) in future. Concurrent Funge-98 is supported.

RFunge follows the spec and passes the Mycology test suite, but it does not currently suport many fingerprints. The performance of rfunge is broadly similar to cfunge and CCBI in many cases, making it one of the faster Befunge-98 interpreters available.

Much like cfunge, the rfunge's command-line interface supports a sandbox mode in which instructions like i, o and = are disabled.

RFunge is (in principle) embeddable, and beside the main Rust API, there is a WASM API used for the web version. It should run on most systems supported by Rust (tested on Linux, MacOS, Windows and WASM).

WebAssembly

RFunge can run in the browser. Try it out here! In the browser, = executes JavaScript code rather than traditional shell commands.

Unicode Funge-98

To my knowledge, rfunge is the first interpreter to implement Unicode Funge-98. In Unicode mode, source files are read in as UTF-8, and the instructions ~ and , read and write unicode characters rather than bytes. This shouldn't make a difference to most programs, unless the files contain bytes > 127, they're trying to read and write binary data, or they're trying to talk to the user in an encoding other than Latin-1.

While systems with multi-byte characters are explicitly allowed by the spec, rfunge also features a traditional binary mode for compatibility with programs that require it (such as Mycology).

Handprint

The native build uses handprint 0x52464e47 ('RFNG'), the WebAssembly build uses handprint 0x52464e57 ('RFNW').

How to build (native)

By default, rfunge is built with support for a GUI display for the TURT fingerprint, but without support for NCRS (ncurses). To build with the default features, run

cargo build --release

The binary will be placed under target.

To build without the GUI, run

cargo build --release --no-default-features

and to build with NCRS support, run

cargo build --release --features ncurses

Building with NCRS will only work on a UNIX system (Linux, MacOS) with the ncurses library and header(s) and a C compiler. It will not work on Windows.

To install, look into the options for cargo install.

How to build (WebAssembly)

You will need wasm-pack to build the WASM package. If wasm-pack is installed, you can run ./build_wasm.sh to build; the WASM binary, and a wrapper script will be placed in webapp/rfunge_wasm/.

To try the actual web UI, navigate into webapp and run the dev script with your favourite JavaScript package manager

cd webapp
npm install
npm run dev

rfunge's People

Contributors

tjol avatar

Stargazers

 avatar

Watchers

 avatar  avatar

rfunge's Issues

Some thoughts on edge cases

Hey, after you pinged me at cwesson/funge-plus-plus#1 I took a look at https://github.com/tjol/rfunge/wiki/Undefined-behaviour-and-known-bugs out of curiosity and had a few thoughts. I haven't given much thought to Funge business in years, so you managed to nerd-snipe me. ๐Ÿ˜„

(An e-mail might've been better suited for this but I figured a GitHub issue is fine too, and maybe this is interesting to someone else out there.)

I also noticed your blog at https://tjol.eu/blog.html โ€” good job getting CCBI compiled, I actually feared it would be more work these days. FWIW, I also offer the binaries at https://deewiant.iki.fi/projects/ccbi/ which I think should work on most modern systems still.

Anyway, to the actual topics at hand.

What happens when you cross the edge?

RFunge takes the view that the program is in theory surrounded by an infinite amount of spaces, and should act that way whether these spaces were ever physically present in the file or not.

To be pedantic, the Funge-98 spec points out that the space ranges across [i32::MIN, i32::MAX] (or equivalently for non-32-bit implementations). So I'd argue that if one writes a # at the cell at i32::MAX and executes it eastwards, it should jump over the cell at i32::MIN.

FBBI and jsFunge-98 make the curious choice of having # and ' behave like in CCBI, but having " behave like in rcFunge.

"choice" is a bit generous... I don't think these kinds of edge cases were given much thought anywhere before I tried to formalize things a bit with Mycology, so these types of weirdnesses tend to be the result of implementation quirks. I think you get this behaviour if you implement # and ' as moving the IP without checking for wraparound (i.e. simply position += delta) and " as just setting a flag and relying on the normal IP movement (which practically must handle wraparound) for it.

Edge cases of k

Figuring out k was a seemingly never-ending source of problems. I remember having several discussions with @VorpalBlade (and other #esoteric regulars at the time) about it, and both CCBI and cfunge saw a number of tweaks.

Looking at it now, I think CCBI gets 0k wrong and rfunge and cfunge get it right. (And all three get positive k right, and cfunge's choice to reflect on negative k is probably the sanest option of the bunch.) Although apparently I explicitly changed CCBI away from that behaviour in Deewiant/CCBI@3c77413... glancing over my IRC logs from 2008โ€“2009 suggests that even at the time I thought that was wrong, so I wonder what prompted it.

k and t

Sorry for having CCBI be broken here. I recall discussing this in the cfunge context and I think at the time I was already starting to be a bit burnt out on CCBI so I never really investigated it properly.


One more source of k "fun" that you haven't mentioned is the topic of nested k, especially combined with instructions that move the IP like #, or ones that also affect the stack while doing so like '. I doubt Mycology tests it (too much of a headache to think about, too many potential behaviours to try to recover from, etc.), but it's one of those things that will definitely cause different kinds of weirdness in different interpreters. In general the topic of "where is the IP during the execution of k" is not very well defined. (I guess you've already run into some of that in VorpalBlade/cfunge#4 .) Consider for example 12kk'abcde@:

  1. On hitting the first k, one should find k to be the instruction to execute twice.
  2. When the inner k is executed for the first time, you can already argue about what instruction it should run: Either, since the IP hasn't moved from the outer k yet, it should find itself, which effectively reduces kk to n (I think?), or, to be more interesting, it should find the next instruction from the inner k, i.e. '.
  3. So assuming the inner k executes ', it will do so once (since 1 is at the top of the stack at this point). Now it's anyone's guess as to where exactly the ' loads from, but I think that if we're not doing the kk == n interpretation then the execution has to happen from the inner k, so the ' finds ' and hence pushes 39. And then it moves the IP to be on top of the a.
  4. When the inner k executes for the second time, 39 is at the top of the stack, so it'll run 39 times. Now with the IP on top of the a, should it run b? Or the ' again? If the latter, the IP should move right 39 times, pushing a few copies of the whole program on the stack, and the outer k is exited at somewhere around the c or d if my mental arithmetic is correct.

I'm pretty sure CCBI and cfunge differ in the details and I wouldn't be surprised if neither one stands up to scrutiny, but cfunge is probably at least better tested in this respect.

(As a side note, I've been meaning to finish my improved Funge-Space implementation at https://github.com/Deewiant/mushspace and then use https://github.com/Deewiant/hali as a base to build a Rust-based interpreter on top of that, with another pass at correctness and scrutinizing these types of edge cases, for ages, but realistically and sadly it'll probably never happen... Let me know if you need help with something in rfunge instead, though!)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.