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

Tuesday, May 12, 2009

Read parse.y and learn about a colon

In Ruby, there are a lot of usages of colon.

  • Symbol :aaa
  • Symbol with single quotes :'aaa'
  • Symbol with double quotes :"aaa"
  • Conditional operator aaa ? bbb : ccc
  • Class hierarchy A::B

The following is an excerpt from parse.y relates a colon:

case ':':
  c = nextc();
  if (c == ':') {
      if (IS_BEG() ||
          lex_state == EXPR_CLASS || (IS_ARG() && space_seen)) {
          lex_state = EXPR_BEG;
          return tCOLON3;
      }
      lex_state = EXPR_DOT;
      return tCOLON2;
  }
  if (lex_state == EXPR_END || lex_state == EXPR_ENDARG || (c != -1 && ISSPACE(c))) {
      pushback(c);
      lex_state = EXPR_BEG;
      return ':';
  }
  switch (c) {
    case '\'':
      lex_strterm = NEW_STRTERM(str_ssym, c, 0);
      break;
    case '"':
      lex_strterm = NEW_STRTERM(str_dsym, c, 0);
      break;
    default:
      pushback(c);
      break;
  }
  lex_state = EXPR_FNAME;
  return tSYMBEG;

If the next character of ':' is ':', in a nutshell if '::' has come, it returns tCOLON3 (:: at the very left) or tCOLON2 (:: at the right hand). Otherwise if the colon is just after expressions, it's a conditional operator. Ditto if the next character is a space. Otherwise finally the colon is a prefix of symbol.

I've never known that we can have a newline after ::!

class A::

B
end

It's valid.

OK... So, let's try to add a new literal :-) which has equivalent to =>.

diff --git a/parse.y b/parse.y
index e2e92ce..8e49bf4 100644
--- a/parse.y
+++ b/parse.y
@@ -7082,6 +7082,9 @@ parser_yylex(struct parser_params *parser)

       case ':':
         c = nextc();
+        if (c == '-' && nextc() == ')') {
+            return tASSOC;
+        }
         if (c == ':') {
             if (IS_BEG() ||
                 lex_state == EXPR_CLASS || (IS_ARG() && space_seen)) {

That's easy.

$ ./ruby -e 'p({ 1 :-) 2 })'
{1=>2}

cool!

No comments:

Post a Comment

Followers