Skip to content

Commit

Permalink
use builtin for RubyVM::AbstractSyntaxTree.
Browse files Browse the repository at this point in the history
Define RubyVM::AbstractSyntaxTree in ast.rb
with __builtin functions.
  • Loading branch information
ko1 committed Nov 8, 2019
1 parent e2a45cb commit a47d058
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 129 deletions.
1 change: 1 addition & 0 deletions .document
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ prelude.rb
rbconfig.rb

trace_point.rb
ast.rb

# the lib/ directory (which has its own .document file)
lib
Expand Down
142 changes: 15 additions & 127 deletions ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "node.h"
#include "vm_core.h"
#include "iseq.h"
#include "builtin.h"

static VALUE rb_mAST;
static VALUE rb_cNode;
Expand Down Expand Up @@ -80,20 +81,8 @@ ast_parse_done(rb_ast_t *ast)
return ast_new_internal(ast, (NODE *)ast->body.root);
}

/*
* call-seq:
* RubyVM::AbstractSyntaxTree.parse(string) -> RubyVM::AbstractSyntaxTree::Node
*
* Parses the given _string_ into an abstract syntax tree,
* returning the root node of that tree.
*
* SyntaxError is raised if the given _string_ is invalid syntax.
*
* RubyVM::AbstractSyntaxTree.parse("x = 1 + 2")
* # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-1:9>
*/
static VALUE
rb_ast_s_parse(VALUE module, VALUE str)
ast_s_parse(rb_execution_context_t *ec, VALUE module, VALUE str)
{
return rb_ast_parse_str(str);
}
Expand All @@ -108,21 +97,8 @@ rb_ast_parse_str(VALUE str)
return ast_parse_done(ast);
}

/*
* call-seq:
* RubyVM::AbstractSyntaxTree.parse_file(pathname) -> RubyVM::AbstractSyntaxTree::Node
*
* Reads the file from _pathname_, then parses it like ::parse,
* returning the root node of the abstract syntax tree.
*
* SyntaxError is raised if _pathname_'s contents are not
* valid Ruby syntax.
*
* RubyVM::AbstractSyntaxTree.parse_file("my-app/app.rb")
* # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-31:3>
*/
static VALUE
rb_ast_s_parse_file(VALUE module, VALUE path)
ast_s_parse_file(rb_execution_context_t *ec, VALUE module, VALUE path)
{
return rb_ast_parse_file(path);
}
Expand Down Expand Up @@ -207,25 +183,8 @@ script_lines(VALUE path)
return lines;
}

/*
* call-seq:
* RubyVM::AbstractSyntaxTree.of(proc) -> RubyVM::AbstractSyntaxTree::Node
* RubyVM::AbstractSyntaxTree.of(method) -> RubyVM::AbstractSyntaxTree::Node
*
* Returns AST nodes of the given _proc_ or _method_.
*
* RubyVM::AbstractSyntaxTree.of(proc {1 + 2})
* # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:35-1:42>
*
* def hello
* puts "hello, world"
* end
*
* RubyVM::AbstractSyntaxTree.of(method(:hello))
* # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-3:3>
*/
static VALUE
rb_ast_s_of(VALUE module, VALUE body)
ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body)
{
VALUE path, node, lines;
int node_id;
Expand Down Expand Up @@ -274,19 +233,8 @@ node_type_to_str(const NODE *node)
return (ruby_node_name(nd_type(node)) + rb_strlen_lit("NODE_"));
}

/*
* call-seq:
* node.type -> symbol
*
* Returns the type of this node as a symbol.
*
* root = RubyVM::AbstractSyntaxTree.parse("x = 1 + 2")
* root.type # => :SCOPE
* call = root.children[2]
* call.type # => :OPCALL
*/
static VALUE
rb_ast_node_type(VALUE self)
ast_node_type(rb_execution_context_t *ec, VALUE self)
{
struct ASTNodeData *data;
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
Expand Down Expand Up @@ -668,92 +616,53 @@ node_children(rb_ast_t *ast, NODE *node)
rb_bug("node_children: unknown node: %s", ruby_node_name(type));
}

/*
* call-seq:
* node.children -> array
*
* Returns AST nodes under this one. Each kind of node
* has different children, depending on what kind of node it is.
*
* The returned array may contain other nodes or <code>nil</code>.
*/
static VALUE
rb_ast_node_children(VALUE self)
ast_node_children(rb_execution_context_t *ec, VALUE self)
{
struct ASTNodeData *data;
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);

return node_children(data->ast, data->node);
}

/*
* call-seq:
* node.first_lineno -> integer
*
* The line number in the source code where this AST's text began.
*/
static VALUE
rb_ast_node_first_lineno(VALUE self)
ast_node_first_lineno(rb_execution_context_t *ec, VALUE self)
{
struct ASTNodeData *data;
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);

return INT2NUM(nd_first_lineno(data->node));
}

/*
* call-seq:
* node.first_column -> integer
*
* The column number in the source code where this AST's text began.
*/
static VALUE
rb_ast_node_first_column(VALUE self)
ast_node_first_column(rb_execution_context_t *ec, VALUE self)
{
struct ASTNodeData *data;
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);

return INT2NUM(nd_first_column(data->node));
}

/*
* call-seq:
* node.last_lineno -> integer
*
* The line number in the source code where this AST's text ended.
*/
static VALUE
rb_ast_node_last_lineno(VALUE self)
ast_node_last_lineno(rb_execution_context_t *ec, VALUE self)
{
struct ASTNodeData *data;
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);

return INT2NUM(nd_last_lineno(data->node));
}

/*
* call-seq:
* node.last_column -> integer
*
* The column number in the source code where this AST's text ended.
*/
static VALUE
rb_ast_node_last_column(VALUE self)
ast_node_last_column(rb_execution_context_t *ec, VALUE self)
{
struct ASTNodeData *data;
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);

return INT2NUM(nd_last_column(data->node));
}

/*
* call-seq:
* node.inspect -> string
*
* Returns debugging information about this node as a string.
*/
static VALUE
rb_ast_node_inspect(VALUE self)
ast_node_inspect(rb_execution_context_t *ec, VALUE self)
{
VALUE str;
VALUE cname;
Expand All @@ -772,35 +681,14 @@ rb_ast_node_inspect(VALUE self)
return str;
}

#include "load_ast.inc"

void
Init_ast(void)
{
/*
* AbstractSyntaxTree provides methods to parse Ruby code into
* abstract syntax trees. The nodes in the tree
* are instances of RubyVM::AbstractSyntaxTree::Node.
*
* This class is MRI specific as it exposes implementation details
* of the MRI abstract syntax tree.
*/
rb_mAST = rb_define_module_under(rb_cRubyVM, "AbstractSyntaxTree");
/*
* RubyVM::AbstractSyntaxTree::Node instances are created by parse methods in
* RubyVM::AbstractSyntaxTree.
*
* This class is MRI specific.
*/
rb_cNode = rb_define_class_under(rb_mAST, "Node", rb_cObject);

rb_undef_alloc_func(rb_cNode);
rb_define_singleton_method(rb_mAST, "parse", rb_ast_s_parse, 1);
rb_define_singleton_method(rb_mAST, "parse_file", rb_ast_s_parse_file, 1);
rb_define_singleton_method(rb_mAST, "of", rb_ast_s_of, 1);
rb_define_method(rb_cNode, "type", rb_ast_node_type, 0);
rb_define_method(rb_cNode, "first_lineno", rb_ast_node_first_lineno, 0);
rb_define_method(rb_cNode, "first_column", rb_ast_node_first_column, 0);
rb_define_method(rb_cNode, "last_lineno", rb_ast_node_last_lineno, 0);
rb_define_method(rb_cNode, "last_column", rb_ast_node_last_column, 0);
rb_define_method(rb_cNode, "children", rb_ast_node_children, 0);
rb_define_method(rb_cNode, "inspect", rb_ast_node_inspect, 0);

load_ast();
}
134 changes: 134 additions & 0 deletions ast.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# for ast.c

class RubyVM

# AbstractSyntaxTree provides methods to parse Ruby code into
# abstract syntax trees. The nodes in the tree
# are instances of RubyVM::AbstractSyntaxTree::Node.
#
# This class is MRI specific as it exposes implementation details
# of the MRI abstract syntax tree.
#
module AbstractSyntaxTree

# call-seq:
# RubyVM::AbstractSyntaxTree.parse(string) -> RubyVM::AbstractSyntaxTree::Node
#
# Parses the given _string_ into an abstract syntax tree,
# returning the root node of that tree.
#
# SyntaxError is raised if the given _string_ is invalid syntax.
#
# RubyVM::AbstractSyntaxTree.parse("x = 1 + 2")
# # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-1:9>
def self.parse string
__builtin_ast_s_parse string
end

# call-seq:
# RubyVM::AbstractSyntaxTree.parse_file(pathname) -> RubyVM::AbstractSyntaxTree::Node
#
# Reads the file from _pathname_, then parses it like ::parse,
# returning the root node of the abstract syntax tree.
#
# SyntaxError is raised if _pathname_'s contents are not
# valid Ruby syntax.
#
# RubyVM::AbstractSyntaxTree.parse_file("my-app/app.rb")
# # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-31:3>
def self.parse_file pathname
__builtin_ast_s_parse_file pathname
end

# call-seq:
# RubyVM::AbstractSyntaxTree.of(proc) -> RubyVM::AbstractSyntaxTree::Node
# RubyVM::AbstractSyntaxTree.of(method) -> RubyVM::AbstractSyntaxTree::Node
#
# Returns AST nodes of the given _proc_ or _method_.
#
# RubyVM::AbstractSyntaxTree.of(proc {1 + 2})
# # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:35-1:42>
#
# def hello
# puts "hello, world"
# end
#
# RubyVM::AbstractSyntaxTree.of(method(:hello))
# # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-3:3>
def self.of body
__builtin_ast_s_of body
end

# RubyVM::AbstractSyntaxTree::Node instances are created by parse methods in
# RubyVM::AbstractSyntaxTree.
#
# This class is MRI specific.
#
class Node

# call-seq:
# node.type -> symbol
#
# Returns the type of this node as a symbol.
#
# root = RubyVM::AbstractSyntaxTree.parse("x = 1 + 2")
# root.type # => :SCOPE
# call = root.children[2]
# call.type # => :OPCALL
def type
__builtin_ast_node_type
end

# call-seq:
# node.first_lineno -> integer
#
# The line number in the source code where this AST's text began.
def first_lineno
__builtin_ast_node_first_lineno
end

# call-seq:
# node.first_column -> integer
#
# The column number in the source code where this AST's text began.
def first_column
__builtin_ast_node_first_column
end

# call-seq:
# node.last_lineno -> integer
#
# The line number in the source code where this AST's text ended.
def last_lineno
__builtin_ast_node_last_lineno
end

# call-seq:
# node.last_column -> integer
#
# The column number in the source code where this AST's text ended.
def last_column
__builtin_ast_node_last_column
end

# call-seq:
# node.children -> array
#
# Returns AST nodes under this one. Each kind of node
# has different children, depending on what kind of node it is.
#
# The returned array may contain other nodes or <code>nil</code>.
def children
__builtin_ast_node_children
end

# call-seq:
# node.inspect -> string
#
# Returns debugging information about this node as a string.
def inspect
__builtin_ast_node_inspect
end
end
end
end
Loading

0 comments on commit a47d058

Please sign in to comment.