#Ruby AST - an endeavor to make an ESTree equivalent for Ruby language This project aims to standardize an AST format for Ruby in the same way ESTree project is doing so for ECMAScript. It is still an a very early state, and any contributions or suggestion are most welcome.
#Node
interface Node { // A syntax node
start: number;
end: number;
loc: SourceLocation;
}
#Location
interface Location {
line: number;
column: number;
}
#SourceLocation
interface SourceLocation {
source: string; // program's code
start: Location;
end: Location;
}
#Program
interface Program {
body: [StatementExpression|BEGIN];
}
#BEGIN Expression
interface BEGIN {
body: [StatementExpression|BEGIN]
}
A 'BEGIN' expression. ##example
BEGIN {
def l() return end
alias l _l
}
#Body
interface Body {
block: [StatementExpression]
handler: EnsureClause | null
finalizer: [StatementExpression]
alternate: [StatementExpression]
}
A method or block or 'begin' body. ##example
begin #<body>
#<block>
print "this is the body's block"
raise "some exception"
#</block>
rescue exception #handler
print "Caught #{exception}"
else #alternate
print "No exception"
ensure #finalizer
print "Exception or not, this is going to execute"
end #</body>
#Alias Expression
interface AliasExpression <: StatementExpression {
old: Identifier
new: Identifier
}
An 'alias' expression. ##example
alias _new _old
#Undef Expression
interface UndefExpression <: StatementExpression {
arguments: [Identifier]
}
An 'undef' expression; think of it as reversing a 'def'. ##example
def l() 12 end
print l # prints '12'
undef l
print l # will throw, because 'l' is no undefined
#Modified Statement Expression
interface ModiefiedStatementExpression <: StatementExpression {
modifier: 'if'|'unless'|'while'|'until';
test: Expression;
}
A top level expression followed by 'if', 'unless', 'while', or 'until'. ##example
alias _new _old if false and _old < 12
def l() 12 end unless defined? :l
class L; def l() 12 end end while false
print "12" until true
l = nil or l = 12 if false
#END Statement
interface END {
body: [StatementExpression];
}
An 'END' top-level statement. ##example
END {
print "this runs on exit"
}
print "this runs on start"
#Assignment Expression
interface AssignmentExpression {
operator: string;
left: [MultipleAssignmentList|Expression]
right: [MultipleAssignmentList|Expression]
}
An assignment expression; a list is allowed on its left as well as on its right if it is in top-level. ##example
a, b = 12, 'l' #is the same as (a, b) = (12, 'l')
print a, b = 12, 'l' #is the same as print( a, (b=12), 'l' )
#Command
interface Command {
block: CommandBlock | (null if arguments != null)
arguments: Arguments | (null if block != null)
name: Identifier
}
A command with non-null argument list and/or non-null block. When in the top-level, parentheses can be dropped for arguemnt list. ##example
print "l" do 12 end
print "l" { 12 }
print "l", 12 { 12 }
print "l", 12 do 12 end
#please note the '(' must _immediately_ follow print; otherwise is an argument list only if the construct it contains
# is not a comma-separated list
print("l", 12) do 12 end
print("l", 12) { 12 }
print do 12 end
print { 12 } # please note the {12} thing is not a dictionary; it is a block
print "l"
print "l", 12
print( "l", 12)
#IdCommand
interface IdCommand <: Identifier, Command {
block: null
arguments: null
name: Identifier
}
Either a command with neither an argument list nor a block, or a simple identifier. ##example
def l() 12 end
l #this is an IdCommand resolving to a command at run time
l = 12
l # this is an IdCommand resolving to a simple identifier at run time
#Method Call Expression
interface MethodCall <: Command {
name: MethodIdentifier
object: Expression;
}
A method being called on an object. ##example
a.b 12 # object: a, name: b
a.- 12 # object: a, name: -
(12 * 12).-@ # object: 12 * 12, name: -@
(a - 12).l 12 { 12 } # object: a - 12, name: l
0.~ # object: 0, name: ~
#Super Call Expression
interface SuperCall <: Command {
type: 'SuperCall';
}
A super call; the syntax is identical to that of an ordinary command. ##example
class L < SomeOtherClass
def e()
super "l" do 12 end
super do 12 end
end
end
#Yield Call Expression
interface YieldCall <: Command {
type: 'YieldCall';
}
A yield call; the syntax is identical to that of an ordinary command. ##example
print { yield "l" do 12 end }
#Void Expression
interface VoidExpression {}
A void expression; void expressions are distinguished from "value" expression, probably to keep programmers from doing crazy things like:
while true; a = (break); end
print a
It is rather off-the-mark though, because it still allows programmers to do crazy things like:
while true; a = true && (break); end
print a
It is mostly a euphemism for a 'statement' since Everything Is An Expression (TM) in ruby; the only reason things like 'return', 'break', 'continue', or 'next' are still called expressions in ruby is that, they can be used in a conditional:
while true do
l = false
l ? continue : break
end
Please note the conditional above is itself a void expression; actually, if the consequent and/or alternate of a conditional is a void expression, the conditional is void as a whole; one caveat to beware with void 'expression's is that, they are not combinable(nor compatible) with non-void expressions (a 'non-void expression' is, tautologically, an expression with a value)
false ? 12 : 'l' # is not a void-expression; 12 and 'l' are 'value' expressions
false ? next: 12 # void-expression, because next is a void expression
false ? next: break # void-expression; next and break are void expressions
furthermore, they can not be used as sub-expressions, because they have no inherent value (i.e., they are not even nil; hence the name 'void'):
12 - 'l' # will parse; 12 and 'l' are 'value' expressions
12 - (next) # won't parse because 'next' has no value
Even more, any 'block' expression like 'if', 'begin', etc., will be a void expression if its last expression is a void expression:
if false then 12; break else "l"; c end # this is a void expression
begin 12; break end # this is a void too
Finally, multi-component block expressions (like 'if' with an 'else', or 'begin' with a 'rescue') will turn into void expressions if any of their composing blocks is a void expression (please note this rule applies recursively):
#below, the 'if' expression will not be void, because component block #1 and component block #2 have inherent value
if false then
#component block number 1: consequent; its value is that of its last expression, i.e., "l"
print "l"
"l"
else
#component block number 2: alternate; its value is that of its last expresion, i.e., 12
print 12
12
end #result: either component block #1 or component block number #2
while false do
#below, the 'if' expression will be void because the values of its component #1 and component #2 are incompatible, i.e.,
# one is a 'value' expression, and the other one is not
if false then
#component block number 1: consequent; evaluates to a void expression (in this case, 'break')
l = "l"
break
else
#component block number 2:
l = 12
end #result: either the value of `l=12` (i.e., 12) or `break` (i.e., no value, not even a nil)
end
#Return Expression
interface ReturnExpression <: VoidExpression {
arguments: Arguments;
}
A return expression. ##example
def l()
return 12, *[12, 12]
end
def w(l)
while true do
( l <= 0 ) ? return :
( l -= 1 ) ? (return l)
end
end
#Break Expression
interface BreakExpression <: VoidExpression {
arguments: Arguments;
}
A break expression: ##example
while false; break 12, *[12] end
while false; break end
#Multiple Assignment List Pattern
MultipleAssignmentListPattern {
head: [AssignmentPatternElement]|null
splat: AssignmentPatternElement|null
tail: [AssignmentPatternElement]|null
}
The left hand side of a top-level assignment expression. ##example
a, (b[0], (c, *e)), (*), = [12, [12, [12]], 12, 12, 12, 12, 12, 12, 12, 12, 12]
# a: 12, b[0]: 12, c: 12, e: []
#Multiple Assignment List
MultipleAssignmentList {
head: [AssignmentElement]|null
splat: AssignmentElement|null
tail: [AssignmentElement]|null
}
The right hand side of a top-level assignment expression. ##example
l = 12, *[12], *[12]
#Next Expression
interface NextExpression <: VoidExpression {
arguments: Arguments
}
A next expression. ##example
while false; next 12, *[12] end
while false; false ? next : return end