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) | 
