aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNat Lasseter <Nat Lasseter user@4574.co.uk>2018-02-15 14:50:59 +0000
committerNat Lasseter <Nat Lasseter user@4574.co.uk>2018-02-15 14:50:59 +0000
commitbfed3dfba46a3f39389bdb529e021e266128df67 (patch)
treee624950a22a25c66b3ef83c9f2af99d6aac3e616
Initial Commit
-rw-r--r--parse.rb44
-rw-r--r--patter.rb43
-rw-r--r--readme.textile46
-rw-r--r--test.pr37
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.
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)