Last active
September 25, 2022 09:05
-
-
Save sampersand/0442484fd4fdc0205b3095763acaac13 to your computer and use it in GitHub Desktop.
Monkeypatched knight in ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# Knight in ruby, but with copious amounts of monkey patching :-) | |
class Fn | |
@fns = {} | |
def self.register(name, ...) = @fns[name] = Fn.new(...) | |
def self.lookup(name) = @fns.fetch(name) | |
def initialize(call_args: true, &block) @call_args, @block = call_args, block end | |
def create(&b) = @block.arity.times.map(&b).then { |x| proc { call(x) } } | |
def call(args) = @block.call(*(@call_args ? args.map(&:call) : args)) | |
register 'P' do gets chomp: true end | |
register 'R' do rand 0..0xffff_ffff end | |
register 'B', call_args: false do _1 end | |
register 'C' do _1.call end | |
register 'Q' do exit _1.to_i end | |
register 'D' do _1.tap { |x| print x.inspect } end # cant use `p` as it adds a newline | |
register 'O' do print _1.to_s.dup.tap { |x| x.slice! /\\\z/ or x << "\n" } end | |
register 'L' do _1.to_a.length end | |
register '!' do !_1 end | |
register '~' do -_1.to_i end | |
register 'A' do _1.ord rescue _1.chr end | |
register ',' do [_1] end | |
register '[' do _1[0] end | |
register ']' do _1[1..] end | |
register '+' do _1 + _2.cast(to: _1) end | |
register '-' do _1 - _2.to_i end | |
register '*' do _1 * _2.to_i end | |
register '/' do _1.fdiv(_2.to_i).truncate end | |
register '%' do _1 % _2.to_i end | |
register '^' do _1 ** _2.cast(to: _1.is_a?(Array) ? "" : _1) end | |
register '<' do _1 < _2.cast(to: _1) end | |
register '>' do _1 > _2.cast(to: _1) end | |
register '?' do _1 == _2 end | |
register ';' do _2 end | |
register '&', call_args: false do !(lhs = _1.call) ? lhs : _2.call end | |
register '|', call_args: false do !(lhs = _1.call) ? _2.call : lhs end | |
register '=', call_args: false do _2.call.tap &_1.method(:call=) end | |
register 'W', call_args: false do _2.call until !_1 end | |
register 'I', call_args: false do (!_1 ? _3 : _2).call end | |
register 'G' do _1[_2.to_i, _3.to_i] end | |
register 'S' do (x = _1.dup)[_2.to_i, _3.to_i] = _4.cast to: x; x end | |
end | |
class Object | |
alias call itself | |
def to_i = call.to_i | |
def to_s = call.to_s | |
def to_a = call.to_a | |
def coerce(rhs) = [rhs, to_i] | |
def cast(to:) | |
case to | |
when Integer then to_i | |
when String then to_s | |
when Array then to_a | |
when true, false then !!self | |
end | |
end | |
end | |
class Var | |
@vars = {} | |
def self.new(name) = @vars[name] ||= super() | |
attr_accessor :call | |
def ! = !call | |
end | |
class Proc | |
def ! = !call | |
end | |
class TrueClass | |
def to_i = 1 | |
def to_a = [self] | |
def <(_) = false | |
def >(x) = !x | |
end | |
class FalseClass | |
def to_i = 0 | |
def to_a = [] | |
def <(x) = !!x | |
def >(_) = false | |
end | |
class NilClass | |
def inspect = 'null' | |
end | |
class Array | |
include Comparable | |
alias ** join | |
alias to_i length | |
def to_s = join("\n") | |
alias ! empty? | |
end | |
class Integer | |
undef ord | |
alias ! zero? | |
def to_a = abs.digits.tap { negative? and _1.map! &:-@ }.reverse | |
end | |
class String | |
alias to_a chars | |
alias old_to_i to_i | |
def to_i = sub(/d/i, '@').old_to_i # `0d10`.to_i == 10, not 0. | |
alias ! empty? | |
def parse! | |
case | |
when slice!(/\A([():\s]+|#.*\n)/) then return replace($').parse! | |
when slice!(/\A\d+/) then $&.to_i | |
when slice!(/\A[a-z_][a-z_\d]*/) then Var.new $& | |
when slice!(/\A(?:'([^']*?)'|"([^"]*?)")/) then $+ | |
when slice!(/\A([TF])[A-Z_]*/) then $1 == 'T' | |
when slice!(/\AN[A-Z_]*/) then nil | |
when slice!(/\A@/) then [] | |
when slice!(/\A([A-Z][A-Z_]*|.)/) then return Fn.lookup($&[0]).create { parse! } | |
end.tap { replace $' } | |
end | |
end | |
$0 == __FILE__ and ($*.shift == '-e' ? $*.shift.dup : File.read($*.shift)).parse!.call |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment