Permalink
Browse files

FirstCommit

  • Loading branch information...
yakitorii committed Aug 30, 2017
1 parent 8081826 commit 736c4e88b63747b6a62b5fa555c622145ed96b0a
Showing with 529 additions and 2 deletions.
  1. +19 −0 compile.c
  2. +3 −0 node.h
  3. +21 −2 parse.y
  4. +86 −0 pattern_exec.rb
  5. +27 −0 pm/node/array_node.rb
  6. +39 −0 pm/node/base.rb
  7. +40 −0 pm/node/hash_node.rb
  8. +8 −0 pm/node/integer_node.rb
  9. +16 −0 pm/node/string_node.rb
  10. +9 −0 pm/node/symbol_node.rb
  11. +10 −0 pm/node/variable_node.rb
  12. +86 −0 pm/pattern_lexicer.rb
  13. +36 −0 pm/pattern_match.rb
  14. +129 −0 pm/pattern_tree.rb
View
@@ -231,6 +231,9 @@ struct iseq_compile_data_ensure_node_stack {
#define ADD_CALL_RECEIVER(seq, line) \
ADD_INSN((seq), (line), putself)
#define ADD_VCALL(seq, line, id) \
ADD_SEND_R((seq), (line), (id), INT2FIX(0), NULL, (VALUE)INT2FIX(VM_CALL_FCALL | VM_CALL_VCALL), NULL)
#define ADD_CALL(seq, line, id, argc) \
ADD_SEND_R((seq), (line), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
@@ -4314,6 +4317,22 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popp
#define BEFORE_RETURN debug_node_end()
switch (type) {
case NODE_PATTERN:{
if (!popped) {
VALUE rb_cPattern = rb_const_get(rb_cObject, rb_intern("PatternMatch"));
VALUE pat = node->nd_lit;
ADD_INSN1(ret, line, putobject, rb_cPattern);
ADD_INSN(ret, line, putself);
ADD_VCALL(ret, line, rb_intern("binding"));
ADD_CALL(ret, line, rb_intern("save_binding"), INT2FIX(1));
ADD_INSN(ret, line, pop);
ADD_INSN1(ret, line, putobject, pat);
}
break;
}
case NODE_BLOCK:{
while (node && nd_type(node) == NODE_BLOCK) {
CHECK(COMPILE_(ret, "BLOCK body", node->nd_head,
View
3 node.h
@@ -230,6 +230,8 @@ enum node_type {
#define NODE_PRELUDE NODE_PRELUDE
NODE_LAMBDA,
#define NODE_LAMBDA NODE_LAMBDA
NODE_PATTERN,
#define NODE_PATTERN NODE_PATTERN
NODE_LAST
#define NODE_LAST NODE_LAST
};
@@ -456,6 +458,7 @@ typedef struct RNode {
#define NEW_BMETHOD(b) NEW_NODE(NODE_BMETHOD,0,0,b)
#define NEW_ATTRASGN(r,m,a) NEW_NODE(NODE_ATTRASGN,r,m,a)
#define NEW_PRELUDE(p,b,o) NEW_NODE(NODE_PRELUDE,p,b,o)
#define NEW_PATTERN(p) NEW_NODE(NODE_PATTERN,p,0,0)
RUBY_SYMBOL_EXPORT_BEGIN
View
23 parse.y
@@ -888,7 +888,7 @@ static void token_info_pop_gen(struct parser_params*, const char *token, size_t
%token <node> tNTH_REF tBACK_REF
%token <num> tREGEXP_END
%type <node> singleton strings string string1 xstring regexp
%type <node> singleton strings string string1 xstring regexp pattern
%type <node> string_contents xstring_contents regexp_contents string_content
%type <node> words symbols symbol_list qwords qsymbols word_list qword_list qsym_list word
%type <node> literal numeric simple_numeric dsym cpath
@@ -952,7 +952,7 @@ static void token_info_pop_gen(struct parser_params*, const char *token, size_t
%token tDSTAR "**arg"
%token tAMPER "&"
%token tLAMBDA "->"
%token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG tSYMBOLS_BEG tQSYMBOLS_BEG
%token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG tSYMBOLS_BEG tQSYMBOLS_BEG tPATTERN_BEG
%token tSTRING_DBEG tSTRING_DEND tSTRING_DVAR tSTRING_END tLAMBEG tLABEL_END
/*
@@ -2449,6 +2449,7 @@ primary : literal
| qsymbols
| var_ref
| backref
| pattern
| tFID
{
/*%%%*/
@@ -3700,6 +3701,20 @@ regexp : tREGEXP_BEG regexp_contents tREGEXP_END
$$ = new_regexp($2, $3);
}
;
pattern : tPATTERN_BEG string_contents tSTRING_END
{
VALUE rb_cPattern = rb_const_get(rb_cObject, rb_intern("PatternMatch"));
VALUE pat = rb_funcall(rb_cPattern, rb_intern("new"), 1, $2->nd_lit);
VALUE pm_variables = rb_funcall(pat, rb_intern("pattern_variables"), 0);
int i;
for(i=0; i< RARRAY_LEN(pm_variables); i++){
fprintf(stderr, "parse.y variable: <%s>\n", RSTRING_PTR(RARRAY_AREF(pm_variables, i)));
local_var(rb_intern(RSTRING_PTR(RARRAY_AREF(pm_variables, i))));
}
fprintf(stderr, "parse.y pattern: <%s>\n", RSTRING_PTR($2->nd_lit));
$$ = NEW_PATTERN(pat);
}
words : tWORDS_BEG ' ' tSTRING_END
{
@@ -7589,6 +7604,10 @@ parse_percent(struct parser_params *parser, const int space_seen, const enum lex
SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);
return tSYMBEG;
case 'p':
lex_strterm = NEW_STRTERM(str_squote, term, paren);
return tPATTERN_BEG;
default:
yyerror("unknown type of %string");
return 0;
View
@@ -0,0 +1,86 @@
if %p(_Integer) =~ 0
p 'it is iteger'
end
user = { name: 'yuki', from: 'Fukuoka' }
case user
when %p({name: name, from: 'Hiroshima'})
p "#{name} is a local people. Thank you!"
when %p({name: name, from: _})
p "#{name} is a visitor. welcome!"
end
__END__
if %p([:ok, x]) =~ [:ok, 200]
p "Seconnd Element is #{x}"
else
p "Not Match!"
end
if %p([:ok, x]) =~ [:ng, 500]
p "Seconnd Element is #{x}"
else
p "Not Match!"
end
if %p(:p) =~ :p
p "symbol succss"
end
res = {status: 'ok', name: 'ko1'}
if %p({status: 'ok', name: name}) =~ res
p name
else
raise 'error!'
end
if %p({:status => 'ok', :name => name}) =~ res
p name
else
raise 'error!'
end
if %p([x, :y, { :test => z, "array" => [5, v]}]) =~ [1, :y, { test: 3, "array" => [5, 'a, b']}]
p x
p z
p v
end
if %p( [x, :y, { :test => z, "a" => 1 }] ) =~ [1, :y, { test: 3, "a" => 1}]
p x
p z
end
__END__
if %p([x, :y, [z, "a, b"]]) =~ [1, :y, [5, "a, b"]]
p x
p z
end
__END__
if %p({x: z, y: _}) =~ {x: 7, y: 8}
p 'success!'
p y
end
if %p([x, :x, [[y], z]]) =~ [1, :x, [[5], 4]]
p 'success! 2'
p y
p z
end
__END__
# PatternMatch.save_binding(binding)
y = nil
if (PatternMatch.save_binding(binding); PatternMatch.new("[1, :x, y]")) =~ [1, :x, 5]
p y #=> :y
end
View
@@ -0,0 +1,27 @@
require_relative './base.rb'
module Node
class ArrayNode < Base
TYPE = 'Array'
def match?(args, result: {})
check_class(args)
check_length(args)
result = check_elements(args, result)
result
end
def elements
@val
end
def add_element(element)
@val << element
end
def check_elements(args, result)
args.each.with_index do |arg, i|
result = elements[i].match?(arg, result: result)
end
result
end
end
end
View
@@ -0,0 +1,39 @@
module Node
class PatternMatchError < StandardError
def initialize(expected:, got:)
message = "expected value is #{expected} but got #{got}"
super(message)
end
end
class ClassNotMatchError < PatternMatchError; end
class LengthNotMatchError < PatternMatchError; end
class ValueNotMatchError < PatternMatchError; end
class Base
attr_reader :val
def initialize(val = nil)
@val = val
end
def match?(args, result: {})
check_class(args)
unless @val == args
raise ValueNotMatchError.new(expected: @val, got: args)
end
result
end
def check_class(args)
expected = self.class::TYPE
got = args.class.to_s
expected == got || raise(ClassNotMatchError.new(expected: expected, got: got))
end
def check_length(args)
expected = args.length
got = elements.length
expected == got || raise(LengthNotMatchError.new(expected: expected, got: got))
end
end
end
View
@@ -0,0 +1,40 @@
module Node
class HashNode < Base
TYPE = 'Hash'.freeze
def match?(args, result: {})
check_class(args)
check_length(args)
result = check_elements(args, result)
result
end
def add_element(element)
@val[element[:key]] = element[:val]
end
private
def elements
@val
end
def check_elements(args, result)
args.each do |k, v|
element_k, element_v = search_element(k)
if element_v
result = element_v.match?(v, result: result)
end
end
result
end
def search_element(arg_key)
elements.find do |k, v|
k.match? arg_key
rescue PatternMatchError
next
end
end
end
end
View
@@ -0,0 +1,8 @@
module Node
class IntegerNode < Base
TYPE = 'Integer'.freeze
def initialize(val)
@val = val.to_i
end
end
end
View
@@ -0,0 +1,16 @@
module Node
class StringNode < Base
TYPE = 'String'.freeze
def initialize(val)
@val = val.gsub(/^('|")/, '').gsub(/('|")$/, '')
end
def match?(args, result: {})
check_class(args)
unless @val == args
raise ValueNotMatchError.new(expected: @val, got: args)
end
result
end
end
end
View
@@ -0,0 +1,9 @@
module Node
class SymbolNode < Base
TYPE = 'Symbol'.freeze
def initialize(val)
@val = val.gsub(':', '').to_sym
end
end
end
View
@@ -0,0 +1,10 @@
module Node
class VariableNode < Base
TYPE = :varable
def match?(args, result: {})
return result if @val == '_'
result.merge({ @val.to_s => args })
end
end
end
Oops, something went wrong.

0 comments on commit 736c4e8

Please sign in to comment.