Awesome
Ohm
Ohm is a stack-oriented programming language inspired by 05AB1E and Jelly designed specifically for code golf.
Does tacit programming make no sense to you, but you really wish you could use Jelly's links? If so, Ohm is the language for you.
Interested in Ohm, but don't want to clone the repository? Thanks to Dennis, there is an online interpreter available on TryItOnline.
Programs and Syntax
Check the full list of components for more info!
The Stack
Ohm uses a stack memory model. Think of the stack as a big array that every component of an Ohm circuit interacts with. For example, when the instruction pointer hits a number, it will push that number to the stack and continue, while the +
component pops two elements off the stack, adds them, and pushes their result. Thus, the following circuit will output 15.
13 2+
(The numbers have to be separated with a no-op (space, in this case) since Ohm continues parsing number literals until there are no more digits left.)
Blocks
Conditional statements and loops in Ohm are handled by a construct called a block. (If you're familiar with Ruby, it's pretty similar to Ruby's blocks.) They're essentially sections of code that are executed differently depending on what component they're attached to. Some components that use them are ?
for if statements, :
for for-each loops, ⁇
for array select/filtering, and €
for array mapping.
If/Else
If you want to add an else
clause to an if statement, just place the ¿
component before the end of the block and put the alternate code in between the two.
Example
0?"code for truthy condition"¿"code for falsy condition";
Auto-Pushing
Most array-looping components like €
, ⁇
, and ‼
will automatically push the current value to the top of the stack, meaning that _
does not have to be explicitly called to get the value. There is one exception to this: the :
(foreach) component. Because of the different use cases for :
, the value is not automatically pushed and has to be explicitly pushed via _
.
Example
5@€^*; Creates a new array with every element multiplied by its index
5@:_,; Prints each element in the array
Implicit Everything
Since Ohm is a golfing language, many things are done implicitly in order to save bytes for the golfer.
- If there is nothing else in the circuit, concluding components like
;
in conditional/loop blocks and"
in string literals are inferred and do not have to be explicitly input.- One exception to this is that multi-line strings must be terminated. (i.e.
"foo¶bar
will not work, must use"foo¶bar"
)
- One exception to this is that multi-line strings must be terminated. (i.e.
- If there are not enough items on the stack when a component tries to pop from it, Ohm will push user input to the stack until there are enough.
- If a circuit has not printed anything once execution completes, the top element of the stack will automatically be printed.
Vectorization
Most components will automatically vectorize, meaning that if you pass in an array(s), it will automatically perform its function over those arguments. For example, passing [1, 2, 3]
to the ²
component will return [1, 4, 9]
. This is more efficient than mapping or using the «
component.
Wires
Wires are a way to splinter your code into different functions (similar to links in Jelly). New wires are placed on a separate line (or separated with a pilcrow ¶
), and the top-most wire is always executed as the main wire.
The Ω
component will execute the wire below the current one, whereas Θ
will execute the one above it, and Φ
will pop an element from the stack and execute the wire at that index.
Example
25@Ωτ@ΩΣ
:^²_-
As you can see, it saves bytes by only requiring the :
block to be declared once.
Base 255
The B
component can handle input bases up to 255. Because of how efficient base 255 is at storing numbers, Ohm comes with a built-in to convert base 255 back to base 10 for use in a circuit. Just surround the base 255 number with “
. (Here's a base 255 conversion script for your convenience.)
String Compression
Ohm uses a slightly-modified version of the Smaz compression library. Inside Ohm circuits, compressed string literals are delimited by ”
characters. In order to generate a compressed string, use the Ohm::Smaz.compress
method or the ·c
component in a circuit.
What's New?
The release of Ohm v2 brought a few new changes, namely:
- Instead of CP437, Ohm now uses its own custom code page.
true
/false
values have been replaced with0
and1
.- Network access is now made possible with
·G
, but safe mode will disable it.
Running
The Ohm interpreter is written in Ruby 2.x (tested on >= 2.2.10). The core interpreter relies on RSmaz for string compression and Ruby/GSL for polynomial solving, and the unit tests rely on RSpec, Timecop, and Rake.
NOTE: As Ruby 2.2.x is now out of security maintenance phase, the Ohm interpreter will soon stop supporting the 2.2.x branch and move to 2.3.x for the minimum supported version.
To install dependencies for normal use, run bundle install --without test
. To install unit testing dependencies, run bundle install
normally.
Tests
To run unit tests, run rake
.
Interpreter Options
Flag | Usage |
---|---|
-c, --code-page | Reads the given file with the Ohm encoding (default UTF-8). |
-d, --debug | Activates debug mode, which prints the current command and stack at every iteration. |
-e, --eval | Evaluates the given circuit as Ohm code. |
-h, --help | Prints usage help. |
-l, --length | Prints the length of the program. |
-s, --safe | Activates safe mode, which disables components like ·G that may have unsafe side effects. |
-t, --time | Shows the time taken to execute (in seconds) after completion. |
Troubleshooting
When using the -e
flag for executing from the terminal, make sure your terminal is in UTF-8 mode. This can be achieved on Windows with the command chcp 65001
. If the terminal is in the incorrect encoding, Ruby will raise an Encoding::CompatibilityError
when trying to use non-ASCII characters (in my experience).
TODO
- ¯\_(ツ)_/¯