Blogged by Ujihisa. Standard methods of programming and thoughts including Clojure, Vim, LLVM, Haskell, Ruby and Mathematics written by a Japanese programmer. github/ujihisa

Monday, May 18, 2009

Pseudo URI Literal

A URI notation is easy to be distinguished. There is almost no confusion about it. Therefore it may be OK that some programming languages have URI Literal. Unfortunately, I have never seen.

I added a something like a URI literal into Ruby.

def http(x)
  "http://#{x}"
end

class Symbol
  def /(o)
    o
  end
end

class String
  def method_missing(*a, &b)
    raise unless a.size == 1
    "#{self}.#{a.first}"
  end

  def /(o)
    "#{self}/#{o}"
  end
end

def method_missing(*a, &b)
  raise unless a.size == 1
  a.first.to_s
end

p http://www.google.com/this/is/a/pen.html
#=> "http://www.google.com/this/is/a/pen.html"

Although this snippet supports only http, it is easy to be extended to handle https, ftp or gopher.

Added on 2009-05-20

I fixed the code to support % notation and to return a URI object by a URI literal as _tad_ suggested. The new code is below:

require 'uri'

def http(x)
  URI.parse "http://#{x}"
end

class Symbol
  def /(o)
    o
  end
end

class String
  def method_missing(*a, &b)
    raise unless a.size == 1
    "#{self}.#{a.first}"
  end

  def /(o)
    "#{self}/#{o}"
  end

  def %(n)
    "#{self}%#{n}"
  end
end

class Integer
  def method_missing(*a, &b)
    raise unless a.size == 1
    "#{self}.#{a.first}"
  end
end

def method_missing(*a, &b)
  raise unless a.size == 1
  a.first.to_s
end

p http://www.google.com/this/is/a/pen.html
#=> #<URI::HTTP:0x7a8c8 URL:http://www.google.com/this/is/a/pen.html>

p http://www.google.com/this/is/a/aaa%20.html
#=> #<URI::HTTP:0x79c98 URL:http://www.google.com/this/is/a/aaa%20.html>

To tell the truth, I finished writing the code in a short time, but at that time blogger.vim didn't work. It tool very long time to fix blogger.vim, and then finally I succeeded it. blogger.vim will be version up soon.

Visited SFU: Simon Fraser University

Today I visited SFU Burnaby campus.

Heron

It took an hour to get to SFU. I had to transfer 2 times. The bus from the nearest station, the Production Way/University Station, to the campus was absolutely congested with students. I remembered the terrible commuter bus of my high school in Japan.

Bus

Meanwhile the campus was cool. There was something like relic atmosphere. I remembered the Japanese famous game Shadow of the Colossus.

Cafeteria

I took an espresso in a cafeteria and then I took a class about the Human Interface.

Path

Garden

And then I looked around mainly Computing Science department. I wanted to talk with people there but I was too nervous to do it.

Campus map

Reflection

After that I went to a library and read some journals about programming languages.

Library

Library2

Blogger.vim 1.0 Released

I wrote a Vim script blogger.vim which handles blogger (blogspot) by Vim. This entry is powered by the baby blogger.vim. Blogger.vim is the only one vim script which handles Blogger using metarw.

Screenshot of blogger.vim

I wrote a ruby script blogger.rb and used it for blogger.vim. Blogger.rb is separated from blogger.vim, so you don't need if_ruby option for your vim.

Blogger.vim 1.0 has a lot of known bugs and unknown bugs. If you find a bug, please let me know it after reading the known bugs section of README.md.

enjoy!

Thursday, May 14, 2009

Memory exhausted in a deep nested array literal

When I was reading '[' section of parser.y,

7190       case '[':
7191         paren_nest++;

I got interested in how it will happen when paren_nest becomes huge. I tried this script:

(9995..11000).each do |n|
  p n
  eval '['*n + ']'*n
end

The result was

/var/folders/Dz/Dz5WpFSZGUaFLA8jp8kT5E+++TM/-Tmp-/v258465/130:3: (eval):1: compile error (SyntaxError)
(eval):1: memory exhausted
...[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]...
                              ^
  from /var/folders/Dz/Dz5WpFSZGUaFLA8jp8kT5E+++TM/-Tmp-/v258465/130:1:in `eval'
  from /var/folders/Dz/Dz5WpFSZGUaFLA8jp8kT5E+++TM/-Tmp-/v258465/130:3
  from /var/folders/Dz/Dz5WpFSZGUaFLA8jp8kT5E+++TM/-Tmp-/v258465/130:1:in `each'
  from /var/folders/Dz/Dz5WpFSZGUaFLA8jp8kT5E+++TM/-Tmp-/v258465/130:1

hmm

Wednesday, May 13, 2009

Fixed uri-open of Termtter

Termtter's uri-open plugin

I committed some to Termtter. The following diff is the summary of my patches today.

diff --git a/lib/plugins/uri-open.rb b/lib/plugins/uri-open.rb
index 0afe73f..06a521b 100644
--- a/lib/plugins/uri-open.rb
+++ b/lib/plugins/uri-open.rb
@@ -8,44 +8,43 @@ module Termtter::Client
     :points => [:output],
     :exec_proc => lambda {|statuses, event|
       statuses.each do |s|
-        public_storage[:uris] += s[:text].scan(%r|https?://[^\s]+|)
+        public_storage[:uris] = s[:text].scan(%r|https?://[^\s]+|) + public_storage[:uris]
       end
     }
   )

   def self.open_uri(uri)
-    unless config.plugins.uri_open.browser.empty?
-      system config.plugins.uri_open.browser, uri
-    else
-      case RUBY_PLATFORM
-      when /linux/
-        system 'firefox', uri
-      when /mswin(?!ce)|mingw|bccwin/
-        system 'explorer', uri
+    cmd =
+      unless config.plugins.uri_open.browser.empty?
+        config.plugins.uri_open.browser
       else
-        system 'open', uri
+        case RUBY_PLATFORM
+        when /linux/; 'firefox'
+        when /mswin(?!ce)|mingw|bccwin/; 'explorer'
+        else; 'open'
+        end
       end
-    end
+    system cmd, uri
   end

   register_command(
     :name => :'uri-open', :aliases => [:uo],
-    :exec_proc => lambda{|arg|
+    :exec_proc => lambda {|arg|
       case arg
-      when /^\s+$/
-        public_storage[:uris].each do |uri|
-          open_uri(uri)
-        end
-        public_storage[:uris].clear
+      when ''
+        open_uri public_storage[:uris].shift
       when /^\s*all\s*$/
-        public_storage[:uris].each do |uri|
-          open_uri(uri)
-        end
-        public_storage[:uris].clear
+        public_storage[:uris].
+          each {|uri| open_uri(uri) }.
+          clear
       when /^\s*list\s*$/
-        public_storage[:uris].each_with_index do |uri, index|
-          puts "#{index}: #{uri}"
-        end
+        public_storage[:uris].
+          enum_for(:each_with_index).
+          to_a.
+          reverse.
+          each  do |uri, index|
+            puts "#{index}: #{uri}"
+          end
       when /^\s*delete\s+(\d+)\s*$/
         puts 'delete'
         public_storage[:uris].delete_at($1.to_i)
@@ -53,19 +52,20 @@ module Termtter::Client
         public_storage[:uris].clear
         puts "clear uris"
       when /^\s*(\d+)\s*$/
-        open_uri(public_storage[:uris][$1.to_i])
-        public_storage[:uris].delete_at($1.to_i)
+        open_uri(public_storage[:uris].delete_at($1.to_i))
+      else
+        puts "**parse error in uri-open**"
       end
     },
-    :completion_proc => lambda{|cmd, arg|
-      %w(all list delete clear).grep(/^#{Regexp.quote arg}/).map{|a| "#{cmd} #{a}"}
+    :completion_proc => lambda {|cmd, arg|
+      %w(all list delete clear).grep(/^#{Regexp.quote arg}/).map {|a| "#{cmd} #{a}" }
     }
   )
 end
-# ~/.termtter
+# ~/.termtter/config
 # plugin 'uri-open'
 #
 # see also: http://ujihisa.nowa.jp/entry/c3dd00c4e0
 #
 # KNOWN BUG
-# * In Debian, exit or C-c in the termtter kills your firefox.
+# * In Debian, exit or C-c in the termtter would kill your firefox.

Lisp like symbol in Ruby

Lisp like symbol in Ruby

I succeeded in adding a lisp like symbol literal to ruby by fixing parse.y.

diff --git a/parse.y b/parse.y
index e2e92ce..c9fbb03 100644
--- a/parse.y
+++ b/parse.y
@@ -6319,6 +6319,9 @@ static int
 parser_yylex(struct parser_params *parser)
 {
     register int c;
+    int cs[1024];
+    int i;
+    char flag; // 't': sTring, 'y': sYmbol
     int space_seen = 0;
     int cmd_state;
     enum lex_state_e last_state;
@@ -6631,8 +6634,26 @@ parser_yylex(struct parser_params *parser)
         return tXSTRING_BEG;

       case '\'':
-        lex_strterm = NEW_STRTERM(str_squote, '\'', 0);
-        return tSTRING_BEG;
+        flag = 'y'; // sYmbol by default
+        for (i=0; i<sizeof(cs); i++) {
+            cs[i] = nextc();
+            if (cs[i] == '\'') {
+                flag = 't'; // sTring
+                break;
+            }
+            if (cs[i] == '\n' || cs[i] == -1) {
+                break; // sYmbol
+            }
+        }
+        while (i >= 0)
+            pushback(cs[i--]);
+        if (flag == 't') {
+            lex_strterm = NEW_STRTERM(str_squote, '\'', 0);
+            return tSTRING_BEG;
+        } else {
+            lex_state = EXPR_FNAME;
+            return tSYMBEG;
+        }

       case '?':
         if (lex_state == EXPR_END || lex_state == EXPR_ENDARG) {

After applying this patch, we can write such like:

p 'aaa'      #=> "aaa"
p 'bbb       #=> :bbb
p 'ccc, true #=> :ccc
             #   true
p :ddd       #=> :ddd

The followings are the methodology how it works:

  1. If the ruby parser finds single quote, the parser peeks the next characters from the next character
  2. The parser stocks each characters into a stack which maximum size is 1024
  3. If the parser finds another single quote, the parser does back tracking with the stack and then considers the following characters as a string.
  4. Otherwise if the parser does not find another single quote within the line, the parser does back tracking with the stack and then considers the following characters as a symbol.

Obviously, there are some known bugs:

  • It cannot handle a line which has 1024+ characters after a quote
  • It confuses in p 'aaa, 'bbb
  • It cannot handle a multi line string

e.g.

p 'aaa
   bbb'

To tell the truth, I wrote this patch just for my curiousity. I don't believe this syntax will harmonize well with Ruby.

Tuesday, May 12, 2009

Cryptic infinite recursion in parse.y

When a single quote comes, parse.y will do:

case '\'':
  lex_strterm = NEW_STRTERM(str_squote, '\'', 0);
  return tSTRING_BEG;

This piece of codes is very same as a part of :'aaa'

NEW_STRTERM is a macro. It is a wrapper of a macro rb_node_newnode, which is a wrapper of a function node_newnode

#define NEW_STRTERM(func, term, paren) \
        rb_node_newnode(NODE_STRTERM, (func), (term) | ((paren) << (CHAR_BIT * 2)), 0)

#define rb_node_newnode(type, a1, a2, a3) node_newnode(parser, type, a1, a2, a3)

static NODE*
node_newnode(struct parser_params *parser, enum node_type type, VALUE a0, VALUE a1, VALUE a2)
{
    NODE *n = (rb_node_newnode)(type, a0, a1, a2);
    nd_set_line(n, ruby_sourceline);
    return n;
}

The last function node_newnode calls rb_node_newnode, that is node_newnode itself, recursively.

Here is the node_newnode which macro is expanded:

static NODE*
node_newnode(struct parser_params *parser, enum node_type type, VALUE a0, VALUE a1, VALUE a2)
{
    NODE *n = node_newnode(parser, type, a0, a1, a2);
    nd_set_line(n, ruby_sourceline);
    return n;
}

It's mysterious. node_newnode seems infinite recursion without any terminate conditions. Why does it work?

Followers