InfraRuby Vision delivers solutions for mobile and web applications.
You can try InfraRuby live in your browser!
Try the InfraRuby statically typed Ruby compiler live in your browser. Try our examples or write your own code.
Follow @InfraRuby on Twitter for news and updates.

The structure of s-expressions

Ruby s-expressions are data representing code. In this post you will see the structure of s-expressions for language features supported by Ruby interpreters and the InfraRuby statically typed Ruby compiler.

An s-expression is an object with a type (a Symbol) and optional arguments. The arguments may be s-expressions or other objects. For example, consider this code to call the puts method:

puts "hello, world"

That code can be generated by the meta-ruby gem with this s-expression:

s(:call, nil, "puts", s(:lit, "hello, world"))

That s-expression has type :call and has three arguments: nil, "puts" and another s-expression with type :lit and argument "hello, world".

All examples in this post will follow this format: source code first and then an s-expression to generate that source code.

literals

value literals

Ruby literals for Integer, Float, Range, String, Symbol and Regexp values are represented by s-expressions with type :lit:

Integer literal
0
s(:lit, 0)
Float literal
3.1
s(:lit, 3.1)
Range literal (inclusive)
1 .. 3
s(:lit, 1 .. 3)
Range literal (exclusive)
1 ... 3
s(:lit, 1 ... 3)
String literal
"hello"
s(:lit, "hello")
Symbol literal
:hello
s(:lit, :hello)
Regexp literal
/hello/
s(:lit, /hello/)
Array literal

Ruby literals for Array objects are represented by s-expressions with type :array:

[
	1,
	2,
]
s(:array,
	s(:lit, 1),
	s(:lit, 2),
)
Hash literal

Ruby literals for Hash objects are represented by s-expressions with type :hash:

{
	"x" => 1,
	"y" => 2,
}
s(:hash,
	s(:lit, "x"), s(:lit, 1),
	s(:lit, "y"), s(:lit, 2),
)

If all the “keys” in the s-expression are s-expressions for Symbol literals then meta-ruby generates a 1.9 syntax hash literal:

{
	x: 1,
	y: 2,
}
s(:hash,
	s(:lit, :x), s(:lit, 1),
	s(:lit, :y), s(:lit, 2),
)
special literals

Ruby literals for nil, true and false are represented by s-expressions:

nil literal
nil
s(:nil)
true literal
true
s(:true)
false literal
false
s(:false)

local variables

Ruby local variable assignments are represented by s-expressions with type :lasgn:

i = 0
s(:lasgn, "i", s(:lit, 0))

Ruby local variable references are represented by s-expressions with type :lvar:

j = i
s(:lasgn, "j", s(:lvar, "i"))

constants

Ruby constants (including modules and classes) are represented by s-expressions with type :const:

STDERR
s(:const, "STDERR")

Ruby constants in a module or class are represented by s-expressions with type :colon2:

Math::PI
s(:colon2, s(:const, "Math"), "PI")

method calls

Ruby method calls are represented by s-expressions with type :call. For example, here is a method call with no explicit receiver and no arguments:

puts
s(:call, nil, "puts")

Any arguments for the method call may be supplied as additional arguments in the s-expression:

puts "hello, world"
s(:call, nil, "puts", s(:lit, "hello, world"))

An explicit receiver may also be supplied:

STDERR.puts
s(:call, s(:const, "STDERR"), "puts")

operators

Ruby operators are just method calls:

j = i + 1
s(:lasgn, "j", s(:call, s(:lvar, "i"), "+", s(:lit, 1)))

The [] operator is just a method call:

e = a[i]
s(:lasgn, "e", s(:call, s(:lvar, "a"), "[]", s(:lvar, "i")))

The []= operator is just a method call:

a[i] = e
s(:call, s(:lvar, "a"), "[]=", s(:lvar, "i"), s(:lvar, "e"))

attribute assignment

Ruby attribute assigments are represented by s-expressions with type :attrasgn:

o.n = 0
s(:attrasgn, s(:lvar, "o"), "n=", s(:lit, 0))

augmented assignment

Ruby augmented assigment operators using the [] and []= operators are represented by s-expressions with type :op_asgn1:

a[i] += 1
s(:op_asgn1, s(:lvar, "a"), s(:lvar, "i"), "+", s(:lit, 1))

Ruby augmented assigment operators for attributes are represented by s-expressions with type :op_asgn2:

o.n += 1
s(:op_asgn2, s(:lvar, "o"), "n=", "+", s(:lit, 1))

compound statements

Ruby compound statements are represented by s-expressions with type :block:

x = 1
y = 2
s(:block,
	s(:lasgn, "x", s(:lit, 1)),
	s(:lasgn, "y", s(:lit, 2)),
)

blocks

Ruby blocks are represented by s-expressions with type :iter:

n.times do |i|
	puts i
end
s(:iter, s(:call, s(:lvar, "n"), "times"), s(:args, "i"),
	s(:call, nil, "puts", s(:lvar, "i"))
)

classes

Ruby classes are represented by s-expressions with type :class:

class XY
	# ...
end
s(:class, "XY", nil,
	# ...
)

eigenclasses

Ruby eigenclasses are represented by s-expressions with type :sclass:

class << self
	# ...
end
s(:sclass, s(:self),
	# ...
)

method definitions

Ruby method definitions are represented by s-expressions with type :defn:

class XY
	class << self
		def [](x, y)
			return new(x, y)
		end
	end
end
s(:class, "XY", nil,
	s(:sclass, s(:self),
		s(:defn, "[]", s(:args, "x", "y"),
			s(:return, s(:call, nil, "new", s(:lvar, "x"), s(:lvar, "y"))),
		)
	)
)

instance variables

Ruby instance variable assignments are represented by s-expressions with type :iasgn:

class XY
	def initialize(x, y)
		@x = x
		@y = y
		return
	end
end
s(:class, "XY", nil,
	s(:defn, "initialize", s(:args, "x", "y"),
		s(:iasgn, "@x", s(:lvar, "x")),
		s(:iasgn, "@y", s(:lvar, "y")),
		s(:return),
	),
)

Ruby instance variable references are represented by s-expressions with type :ivar:

class XY
	def x
		return @x
	end

	def y
		return @y
	end
end
s(:class, "XY", nil,
	s(:defn, "x", s(:args),
		s(:return, s(:ivar, "@x")),
	),
	s(:defn, "y", s(:args),
		s(:return, s(:ivar, "@y")),
	),
)

if statements

Ruby if statements are represented by s-expressions with type :if:

if n == 0
	f0
elsif n == 1
	f1
else
	fn
end
s(:if, s(:call, s(:lvar, "n"), "==", s(:lit, 0)),
	s(:call, nil, "f0"),
	s(:if, s(:call, s(:lvar, "n"), "==", s(:lit, 1)),
		s(:call, nil, "f1"),
		s(:call, nil, "fn"),
	)
)

case statements

Ruby case statements are represented by s-expressions with type :case:

case n
when 0
	f0
when 1
	f1
else
	fn
end
s(:case, s(:lvar, "n"),
s(:when, s(:array, s(:lit, 0)),
	s(:call, nil, "f0"),
),
s(:when, s(:array, s(:lit, 1)),
	s(:call, nil, "f1"),
),
	s(:call, nil, "fn"),
)

exception handling

Ruby rescue statements are represented by s-expressions with type :rescue:

begin
	f
rescue JAVA::java.lang.Throwable
	g
end
s(:rescue,
	s(:call, nil, "f"),
	s(:resbody, s(:array, s(:call, s(:call, s(:call, s(:const, "JAVA"), "java"), "lang"), "Throwable")),
		s(:call, nil, "g"),
	),
)

Ruby ensure statements are represented by s-expressions with type :ensure:

begin
	f
ensure
	g
end
s(:ensure,
	s(:call, nil, "f"),
	s(:call, nil, "g"),
)

Try the InfraRuby statically typed Ruby compiler live in your browser. You can use InfraRuby for your own projects with our free download!

Follow @InfraRuby on Twitter
Copyright © 2011-2017 InfraRuby Vision Limited