diff options
-rw-r--r-- | parse.rb | 44 | ||||
-rw-r--r-- | patter.rb | 43 | ||||
-rw-r--r-- | readme.textile | 46 | ||||
-rw-r--r-- | test.pr | 37 |
4 files changed, 170 insertions, 0 deletions
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.pr >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. @@ -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) |