Skip to content

Instantly share code, notes, and snippets.

@DataKinds
Created November 25, 2025 10:01
Show Gist options
  • Select an option

  • Save DataKinds/46b9cc68b3ded20bc199c864df3f867a to your computer and use it in GitHub Desktop.

Select an option

Save DataKinds/46b9cc68b3ded20bc199c864df3f867a to your computer and use it in GitHub Desktop.
require 'pry'
# stack ops
def pop stack
stack.pop
end
def push(stack, x)
stack.push x
end
def call(stack, fn_sym)
fn = method(fn_sym)
n = fn.arity.abs - 1
puts "CALLING #{fn} ON STACK #{stack} POPPING #{n}" if $DEBUG
xs = (1..n).map do pop stack end
fn[stack, *n]
end
# parser
def lex input
input.split(/\s+/)
end
class Quote
attr_accessor :words
def initialize(words)
@words = words
end
def inspect
"[ #{@words.map(&:inspect).join" "} ]"
end
end
class Comptime
attr_accessor :words
def initialize(words)
@words = words
end
def inspect
"[ #{@words.map(&:inspect).join" "} ]"
end
end
def parse words
out = []
idx = 0
while idx < words.length
word = words[idx]
case word
when '[' # parse quotes
starting = idx+1
depth = 1
while depth > 0
raise "Unbalanced quote brackets" if idx > words.length
peek = words[idx += 1]
depth -= 1 if peek == ']'
depth += 1 if peek == '['
end
ending = idx-1
out << Quote.new(parse words[starting..ending])
when '{' # parse comptime brackets
starting = idx+1
depth = 1
while depth > 0
raise "Unbalanced comptime brackets" if idx > words.length
peek = words[idx += 1]
depth -= 1 if peek == '}'
depth += 1 if peek == '{'
end
ending = idx-1
out << Comptime.new(parse words[starting..ending])
else
out << word
end
idx += 1
end
out
end
# runtime words
def hello(stack, person)
puts "hello, #{person}!"
end
class SumType
def initialize(*variants)
@variants = variants.flatten
end
def +(other_type)
SumType.new(@variants, other_type)
end
end
class ProductType
def initialize(*fields)
@fields = fields.flatten
end
def *(other_type)
ProductType.new(@fields, other_type)
end
end
# runtime
def register(names, fn_sym)
names[fn_sym.name] = fn_sym
end
def run(ast, is_comptime, stack = [], names = {})
register(names, :hello)
ast.each do |term|
if is_comptime
case term
when Comptime
# TODO
end
else
case term
when String # the term is a bare function to call
fn_sym = names[term]
raise "got unrecognized name #{term}" if fn_sym.nil?
call(stack, fn_sym)
when Quote
push(stack, term)
when Comptime
else
push term
end
end
end
return stack, names
end
def full(input)
ast = parse(lex(input))
stack, comptime_names = run(ast, true)
run(ast, false, names = comptime_names)
end
puts parse(lex "hello [ wrld [ ] ]")
puts run(parse(lex "hello [ wrld [ ] ]"), false)
# puts full("hello [ wrld [ ] ]")
pry
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment