From bfed3dfba46a3f39389bdb529e021e266128df67 Mon Sep 17 00:00:00 2001 From: Nat Lasseter Date: Thu, 15 Feb 2018 14:50:59 +0000 Subject: Initial Commit --- parse.rb | 44 ++++++++++++++++++++++++++++++++++++++++++++ patter.rb | 43 +++++++++++++++++++++++++++++++++++++++++++ readme.textile | 46 ++++++++++++++++++++++++++++++++++++++++++++++ test.pr | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+) create mode 100644 parse.rb create mode 100644 patter.rb create mode 100644 readme.textile create mode 100644 test.pr diff --git a/parse.rb b/parse.rb new file mode 100644 index 0000000..5fcfad2 --- /dev/null +++ b/parse.rb @@ -0,0 +1,44 @@ +def sub_vars(string) + outvars = [] + blockvars = [] + vars = string.split(",").map(&:strip) + vars.each do |var| + if var =~ /[a-z_][a-zA-Z0-9_]*?/ then + outvars << "Patter::Var" + blockvars << var + else + outvars << var + end + end + return outvars.join(", "), blockvars.join(", ") +end + +def sub_funs(string, funs) + funs.each do |fun| + string.gsub!(/#{fun}\((.*?)\)/, "#{fun}.call(\\1)") + end + return string +end + +lines = $stdin.readlines.map(&:chomp) +funs = [] + +puts "require './patter'" +puts + +lines.each do |line| + if line =~ /\s*([a-z_][a-zA-Z0-9_]*?)\((.*)\) is\s*$/ then + unless funs.include?($1) then + funs << $1 + puts "#{$1} = Patter::Fun.new" + end + arg, blk = sub_vars($2) + if blk.empty? then + puts "#{$1}.when(#{arg}) do" + else + puts "#{$1}.when(#{arg}) do |#{blk}|" + end + else + puts sub_funs(line, funs) + end +end diff --git a/patter.rb b/patter.rb new file mode 100644 index 0000000..348cbdf --- /dev/null +++ b/patter.rb @@ -0,0 +1,43 @@ +module Patter + class Var; end + + class Fun + def initialize + @patterns = {} + end + + def when(*args, &block) + raise "Block arity does not match number of free variables" if args.count(Var) != block.arity + @patterns[args] = block + end + + def call(*args) + free_vars, block = match(args) + block.call(*free_vars) + end + + alias_method :[], :call + + private + + def match(args) + @patterns.each do |pattern, block| + next if pattern.length != args.length + free_variables = [] + matched = true + pattern.zip(args).each do |pair| + if pair.first == Var then + free_variables << pair.last + next + end + if pair.first != pair.last then + matched = false + break + end + end + return [free_variables, block] if matched + end + raise "Inexhaustive patterns" + end + end +end diff --git a/readme.textile b/readme.textile new file mode 100644 index 0000000..a5c25f2 --- /dev/null +++ b/readme.textile @@ -0,0 +1,46 @@ +h1. Patter + +This is Patter(n Ruby). + +h2. What? + +It's a pattern matching thing for Ruby. It's AWFUL. + +h2. How? + +h3. Patter macro parser + +bc.. $ echo <<. >test.pr +fib(0) is + 1 +end +fib(1) is + 1 +end +fib(x) is + fib(x-1) + fib(x-2) +end + +puts fib(10) +. +$ ruby parse.rb test.rb +$ ruby test.rb + +h3. Include Patter + +bc.. $ echo <<. >test.rb +require './patter' +include Patter + +fib = Fun.new +fib.when(0){1} +fib.when(1){1} +fib.when(Var) do |n| + fib.call(n-1) + fib.call(n-2) +end +. +$ ruby test.rb + +h2. Why? + +Clearly the Eldritch horrors are upon us. diff --git a/test.pr b/test.pr new file mode 100644 index 0000000..77dfb27 --- /dev/null +++ b/test.pr @@ -0,0 +1,37 @@ +zerop(0) is + true +end +zerop(_) is + false +end + +fib(0) is + 1 +end +fib(1) is + 1 +end +fib(x) is + fib(x-1) + fib(x-2) +end + +add(x, y) is + x + y +end + +puts add(1, 2) +puts fib(5) + +putser(string) is + puts string +end +putser("foo") + +varity(_) is + puts "one thing" +end +varity(_, _) is + puts "two things" +end +varity(1) +varity(1,2) -- cgit v1.2.1