From 49d8d32ef5cbb151514541d3302bc3acb9bf514a Mon Sep 17 00:00:00 2001 From: mkarlesky Date: Mon, 11 May 2009 02:15:51 +0000 Subject: [PATCH] added new function prototype parser and treetop gem (not yet folded into cmock proper) and tests; cleaned up file paths in test require statements git-svn-id: http://cmock.svn.sourceforge.net/svnroot/cmock/trunk@91 bf332499-1b4d-0410-844d-d2d48d5cc64c --- config/environment.rb | 2 + lib/cmock_function_prototype_node_classes.rb | 256 ++ lib/cmock_function_prototype_parser.rb | 1034 ++++++ lib/cmock_function_prototype_parser.treetop | 87 + rakefile.rb | 17 +- test/unit/cmock_config_test.rb | 2 +- test/unit/cmock_file_writer_test.rb | 2 +- .../cmock_function_prototype_parser_test.rb | 264 ++ test/unit/cmock_generator_main_test.rb | 2 +- .../cmock_generator_plugin_cexception_test.rb | 2 +- .../cmock_generator_plugin_expect_test.rb | 2 +- .../cmock_generator_plugin_ignore_test.rb | 2 +- test/unit/cmock_generator_utils_test.rb | 5 +- test/unit/cmock_header_parser_test.rb | 4 +- test/unit/cmock_plugin_manager_test.rb | 2 +- test/unit/cmock_unityhelper_parser_test.rb | 2 +- vendor/gems/polyglot-0.2.5/History.txt | 36 + vendor/gems/polyglot-0.2.5/License.txt | 20 + vendor/gems/polyglot-0.2.5/Manifest.txt | 24 + vendor/gems/polyglot-0.2.5/README.txt | 87 + vendor/gems/polyglot-0.2.5/Rakefile | 4 + vendor/gems/polyglot-0.2.5/config/hoe.rb | 71 + .../polyglot-0.2.5/config/requirements.rb | 17 + vendor/gems/polyglot-0.2.5/lib/polyglot.rb | 63 + .../polyglot-0.2.5/lib/polyglot/version.rb | 9 + vendor/gems/polyglot-0.2.5/log/debug.log | 0 vendor/gems/polyglot-0.2.5/script/destroy | 14 + vendor/gems/polyglot-0.2.5/script/generate | 14 + vendor/gems/polyglot-0.2.5/script/txt2html | 74 + vendor/gems/polyglot-0.2.5/setup.rb | 1585 +++++++++ .../gems/polyglot-0.2.5/tasks/deployment.rake | 34 + .../polyglot-0.2.5/tasks/environment.rake | 7 + vendor/gems/polyglot-0.2.5/tasks/website.rake | 17 + .../gems/polyglot-0.2.5/test/test_helper.rb | 2 + .../gems/polyglot-0.2.5/test/test_polyglot.rb | 11 + vendor/gems/polyglot-0.2.5/website/index.html | 100 + vendor/gems/polyglot-0.2.5/website/index.txt | 79 + .../javascripts/rounded_corners_lite.inc.js | 285 ++ .../website/stylesheets/screen.css | 138 + .../polyglot-0.2.5/website/template.rhtml | 48 + vendor/gems/treetop-1.2.5/README | 164 + vendor/gems/treetop-1.2.5/Rakefile | 20 + vendor/gems/treetop-1.2.5/bin/tt | 28 + ...contributing_and_planned_features.markdown | 103 + .../doc/grammar_composition.markdown | 65 + vendor/gems/treetop-1.2.5/doc/index.markdown | 90 + .../pitfalls_and_advanced_techniques.markdown | 51 + .../doc/semantic_interpretation.markdown | 189 ++ vendor/gems/treetop-1.2.5/doc/site.rb | 110 + vendor/gems/treetop-1.2.5/doc/sitegen.rb | 60 + .../doc/syntactic_recognition.markdown | 100 + .../treetop-1.2.5/doc/using_in_ruby.markdown | 21 + .../examples/lambda_calculus/arithmetic.rb | 551 +++ .../lambda_calculus/arithmetic.treetop | 97 + .../arithmetic_node_classes.rb | 7 + .../lambda_calculus/arithmetic_test.rb | 54 + .../examples/lambda_calculus/lambda_calculus | 0 .../lambda_calculus/lambda_calculus.rb | 718 ++++ .../lambda_calculus/lambda_calculus.treetop | 132 + .../lambda_calculus_node_classes.rb | 5 + .../lambda_calculus/lambda_calculus_test.rb | 89 + .../examples/lambda_calculus/test_helper.rb | 18 + vendor/gems/treetop-1.2.5/lib/treetop.rb | 11 + .../treetop/bootstrap_gen_1_metagrammar.rb | 45 + .../treetop-1.2.5/lib/treetop/compiler.rb | 6 + .../lib/treetop/compiler/grammar_compiler.rb | 40 + .../treetop/compiler/lexical_address_space.rb | 17 + .../lib/treetop/compiler/metagrammar.rb | 2955 +++++++++++++++++ .../lib/treetop/compiler/metagrammar.treetop | 404 +++ .../lib/treetop/compiler/node_classes.rb | 19 + .../compiler/node_classes/anything_symbol.rb | 18 + .../node_classes/atomic_expression.rb | 14 + .../compiler/node_classes/character_class.rb | 19 + .../treetop/compiler/node_classes/choice.rb | 31 + .../node_classes/declaration_sequence.rb | 24 + .../treetop/compiler/node_classes/grammar.rb | 28 + .../compiler/node_classes/inline_module.rb | 27 + .../compiler/node_classes/nonterminal.rb | 13 + .../treetop/compiler/node_classes/optional.rb | 19 + .../node_classes/parenthesized_expression.rb | 9 + .../node_classes/parsing_expression.rb | 138 + .../compiler/node_classes/parsing_rule.rb | 55 + .../compiler/node_classes/predicate.rb | 45 + .../compiler/node_classes/repetition.rb | 55 + .../treetop/compiler/node_classes/sequence.rb | 68 + .../treetop/compiler/node_classes/terminal.rb | 20 + .../compiler/node_classes/transient_prefix.rb | 9 + .../compiler/node_classes/treetop_file.rb | 9 + .../lib/treetop/compiler/ruby_builder.rb | 113 + .../lib/treetop/ruby_extensions.rb | 2 + .../lib/treetop/ruby_extensions/string.rb | 42 + .../gems/treetop-1.2.5/lib/treetop/runtime.rb | 5 + .../lib/treetop/runtime/compiled_parser.rb | 95 + .../lib/treetop/runtime/interval_skip_list.rb | 4 + .../runtime/interval_skip_list/head_node.rb | 15 + .../interval_skip_list/interval_skip_list.rb | 200 ++ .../runtime/interval_skip_list/node.rb | 164 + .../lib/treetop/runtime/syntax_node.rb | 72 + .../treetop/runtime/terminal_parse_failure.rb | 16 + .../runtime/terminal_parse_failure_debug.rb | 21 + .../treetop/runtime/terminal_syntax_node.rb | 17 + .../gems/treetop-1.2.5/lib/treetop/version.rb | 9 + 102 files changed, 11956 insertions(+), 13 deletions(-) create mode 100644 lib/cmock_function_prototype_node_classes.rb create mode 100644 lib/cmock_function_prototype_parser.rb create mode 100644 lib/cmock_function_prototype_parser.treetop create mode 100644 test/unit/cmock_function_prototype_parser_test.rb create mode 100755 vendor/gems/polyglot-0.2.5/History.txt create mode 100755 vendor/gems/polyglot-0.2.5/License.txt create mode 100755 vendor/gems/polyglot-0.2.5/Manifest.txt create mode 100755 vendor/gems/polyglot-0.2.5/README.txt create mode 100755 vendor/gems/polyglot-0.2.5/Rakefile create mode 100755 vendor/gems/polyglot-0.2.5/config/hoe.rb create mode 100755 vendor/gems/polyglot-0.2.5/config/requirements.rb create mode 100755 vendor/gems/polyglot-0.2.5/lib/polyglot.rb create mode 100755 vendor/gems/polyglot-0.2.5/lib/polyglot/version.rb create mode 100755 vendor/gems/polyglot-0.2.5/log/debug.log create mode 100755 vendor/gems/polyglot-0.2.5/script/destroy create mode 100755 vendor/gems/polyglot-0.2.5/script/generate create mode 100755 vendor/gems/polyglot-0.2.5/script/txt2html create mode 100755 vendor/gems/polyglot-0.2.5/setup.rb create mode 100755 vendor/gems/polyglot-0.2.5/tasks/deployment.rake create mode 100755 vendor/gems/polyglot-0.2.5/tasks/environment.rake create mode 100755 vendor/gems/polyglot-0.2.5/tasks/website.rake create mode 100755 vendor/gems/polyglot-0.2.5/test/test_helper.rb create mode 100755 vendor/gems/polyglot-0.2.5/test/test_polyglot.rb create mode 100755 vendor/gems/polyglot-0.2.5/website/index.html create mode 100755 vendor/gems/polyglot-0.2.5/website/index.txt create mode 100755 vendor/gems/polyglot-0.2.5/website/javascripts/rounded_corners_lite.inc.js create mode 100755 vendor/gems/polyglot-0.2.5/website/stylesheets/screen.css create mode 100755 vendor/gems/polyglot-0.2.5/website/template.rhtml create mode 100755 vendor/gems/treetop-1.2.5/README create mode 100755 vendor/gems/treetop-1.2.5/Rakefile create mode 100755 vendor/gems/treetop-1.2.5/bin/tt create mode 100755 vendor/gems/treetop-1.2.5/doc/contributing_and_planned_features.markdown create mode 100755 vendor/gems/treetop-1.2.5/doc/grammar_composition.markdown create mode 100755 vendor/gems/treetop-1.2.5/doc/index.markdown create mode 100755 vendor/gems/treetop-1.2.5/doc/pitfalls_and_advanced_techniques.markdown create mode 100755 vendor/gems/treetop-1.2.5/doc/semantic_interpretation.markdown create mode 100755 vendor/gems/treetop-1.2.5/doc/site.rb create mode 100755 vendor/gems/treetop-1.2.5/doc/sitegen.rb create mode 100755 vendor/gems/treetop-1.2.5/doc/syntactic_recognition.markdown create mode 100755 vendor/gems/treetop-1.2.5/doc/using_in_ruby.markdown create mode 100755 vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic.rb create mode 100755 vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic.treetop create mode 100755 vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic_node_classes.rb create mode 100755 vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic_test.rb create mode 100755 vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus create mode 100755 vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus.rb create mode 100755 vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus.treetop create mode 100755 vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus_node_classes.rb create mode 100755 vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus_test.rb create mode 100755 vendor/gems/treetop-1.2.5/examples/lambda_calculus/test_helper.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/bootstrap_gen_1_metagrammar.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/grammar_compiler.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/lexical_address_space.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/metagrammar.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/metagrammar.treetop create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/anything_symbol.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/atomic_expression.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/character_class.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/choice.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/declaration_sequence.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/grammar.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/inline_module.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/nonterminal.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/optional.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/parenthesized_expression.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/parsing_expression.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/parsing_rule.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/predicate.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/repetition.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/sequence.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/terminal.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/transient_prefix.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/treetop_file.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/compiler/ruby_builder.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/ruby_extensions.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/ruby_extensions/string.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/runtime.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/runtime/compiled_parser.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list/head_node.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list/interval_skip_list.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list/node.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/runtime/syntax_node.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/runtime/terminal_parse_failure.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/runtime/terminal_parse_failure_debug.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/runtime/terminal_syntax_node.rb create mode 100755 vendor/gems/treetop-1.2.5/lib/treetop/version.rb diff --git a/config/environment.rb b/config/environment.rb index d51769c..220f685 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -6,6 +6,8 @@ ROOT_PATH = File.expand_path(File.dirname(__FILE__) + "/../") 'vendor/behaviors/lib', 'vendor/hardmock/lib', 'vendor/unity/auto/', + 'vendor/gems/polyglot-0.2.5/lib/', + 'vendor/gems/treetop-1.2.5/lib/', 'test/system/' ].each do |dir| $LOAD_PATH.unshift(File.join(ROOT_PATH, dir)) diff --git a/lib/cmock_function_prototype_node_classes.rb b/lib/cmock_function_prototype_node_classes.rb new file mode 100644 index 0000000..efe8144 --- /dev/null +++ b/lib/cmock_function_prototype_node_classes.rb @@ -0,0 +1,256 @@ + +module CMockFunctionPrototype + + module FunctionPrototypeUtils + def normalize_ptr(ptr_string) + ptr_string.gsub!(/\s+\*/, '*') + ptr_string.gsub!(/\*(\w)/, '* \1') + return ptr_string + end + + def make_cmock_arg_name(index) + return "cmock_arg#{index+1}" + end + end + + + class FunctionPrototypeStandardNode < Treetop::Runtime::SyntaxNode + def get_declaration + return "#{get_return_type} #{get_function_name}#{argument_list.normalized_argument_list}" + end + + def get_return_type + return return_type.text_value + end + + def get_function_name + return name.text_value + end + + def get_argument_list + return argument_list.smart_argument_list + end + + def get_arguments + return argument_list.arguments_array + end + + def get_var_arg + return argument_list.var_arg + end + + def get_typedefs + return argument_list.typedefs_array + end + end + + + class FunctionPrototypeFunctionPointerReturnNode < Treetop::Runtime::SyntaxNode + def get_declaration + return "#{return_type.text_value} (*#{get_function_name}#{function_arglist.normalized_argument_list})#{function_return_arglist.normalized_argument_list}" + end + + def get_return_type + return "#{return_type.text_value} (*)#{function_return_arglist.normalized_argument_list}" + end + + def get_function_name + return name.text_value + end + + def get_argument_list + return function_arglist.smart_argument_list + end + + def get_arguments + return function_arglist.arguments_array + end + + def get_var_arg + return function_arglist.var_arg + end + + def get_typedefs + type_name = "FUNC_PTR_#{get_function_name.upcase}_RETURN_T" + return [ + { :type => get_return_type, + :typename => type_name, + :typedef => "typedef #{return_type.text_value} (*#{type_name})#{function_return_arglist.normalized_argument_list};" }] + end + end + + + class ArgumentListNode < Treetop::Runtime::SyntaxNode + + def initialize(*params) + super(*params) + @var_arg_found = false + end + + def var_arg + return '...' if @var_arg_found + return nil + end + + # produce a simple argument list with pointers and white space normalized + # (i.e. don't add custom param names, etc.) + def normalized_argument_list + list = [] + + arguments.elements.each do |element| + list << element.argument.text_value + end + + return '(void)' if (list.size == 0) + return '(void)' if (list.size == 1 and list[0] == 'void') + return '( ' + list.join(', ') + ' )' + end + + # produce an argument list with pointers and white space normalized as well as auto-generated names for missing argument names + def smart_argument_list + list = [] + + arguments.elements.each_with_index do |element, index| + arg = element.argument + if (arg.class == CMockFunctionPrototype::TypeWithNameNode) + list << arg.formatted_type_and_name_string(index) + elsif (arg.class == CMockFunctionPrototype::FunctionPointerNode) + list << arg.formatted_type_and_name_string(index) + elsif (arg.class == CMockFunctionPrototype::VarArgNode) + @var_arg_found = true + # consume var args + else + list << arg.text_value + end + end + + return 'void' if (list.size == 0) + + return list.join(', ') + end + + def arguments_array + list = [] + + arguments.elements.each_with_index do |element, index| + arg = element.argument + if (arg.class == CMockFunctionPrototype::TypeWithNameNode) + list << arg.type_and_name_token_hash(index) + elsif (arg.class == CMockFunctionPrototype::FunctionPointerNode) + list << arg.type_and_name_token_hash(index, self.parent.name.text_value) + elsif (arg.class == CMockFunctionPrototype::VarArgNode) + # consume var args + elsif (arg.class == CMockFunctionPrototype::VoidNode) + # consume void + else + end + end + + return list + end + + def typedefs_array + list = [] + + arguments.elements.each_with_index do |element, index| + arg = element.argument + if (arg.class == CMockFunctionPrototype::FunctionPointerNode) + list << arg.typedef_hash(index, self.parent.name.text_value) + end + end + + return list + end + end + + + class FunctionPointerNode < Treetop::Runtime::SyntaxNode + include FunctionPrototypeUtils + + def text_value + return "#{return_type.text_value} (*#{name.text_value})#{argument_list.normalized_argument_list}" + end + + def formatted_type_and_name_string(arg_list_index) + func_ptr_name = name.text_value + + if (name.text_value.blank?) + func_ptr_name = make_cmock_arg_name(arg_list_index) + end + + return "#{return_type.text_value} (*#{func_ptr_name})#{argument_list.normalized_argument_list}" + end + + def type_and_name_token_hash(arg_list_index, function_name) + type = "#{return_type.text_value} (*)#{argument_list.normalized_argument_list}" + + return { :type => type, :name => make_cmock_arg_name(arg_list_index) } if (name.text_value.blank?) + return { :type => type, :name => name.text_value } + end + + def typedef_hash(arg_list_index, function_name) + typename = "FUNC_PTR_#{function_name.upcase}_PARAM_#{arg_list_index+1}_T" + type = "#{return_type.text_value} (*)#{argument_list.normalized_argument_list}" + typedef = "typedef #{return_type.text_value} (*#{typename})#{argument_list.normalized_argument_list};" + + return { :type => type, :typename => typename, :typedef => typedef } + end + end + + + class TypeWithNameNode < Treetop::Runtime::SyntaxNode + include FunctionPrototypeUtils + + def text_value + return "#{normalize_ptr(type.text_value)} #{name.text_value}" if not name.text_value.blank? + return "#{normalize_ptr(type.text_value)}" + end + + def formatted_type_and_name_string(arg_list_index) + if (name.text_value.blank?) + return "#{type.text_value} #{make_cmock_arg_name(arg_list_index)}" + end + + return "#{type.text_value} #{name.text_value}" + end + + def type_and_name_token_hash(arg_list_index) + if (name.text_value.blank?) + return { :type => type.text_value, :name => make_cmock_arg_name(arg_list_index)} + end + + return { :type => type.text_value, :name => name.text_value} + end + end + + + class NameNode < Treetop::Runtime::SyntaxNode + def text_value + return super.strip + end + end + + + class TypeNode < Treetop::Runtime::SyntaxNode + include FunctionPrototypeUtils + + def text_value + return normalize_ptr(super.gsub(/\s+/, ' ')).strip + end + end + + + class VoidNode < Treetop::Runtime::SyntaxNode + def text_value + return super.strip + end + end + + + class VarArgNode < Treetop::Runtime::SyntaxNode + def text_value + return super.strip + end + end + +end diff --git a/lib/cmock_function_prototype_parser.rb b/lib/cmock_function_prototype_parser.rb new file mode 100644 index 0000000..e2b2947 --- /dev/null +++ b/lib/cmock_function_prototype_parser.rb @@ -0,0 +1,1034 @@ +module CMockFunctionPrototype + include Treetop::Runtime + + def root + @root || :function_prototype + end + + def _nt_function_prototype + start_index = index + if node_cache[:function_prototype].has_key?(index) + cached = node_cache[:function_prototype][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + r1 = _nt_function_prototype_function_pointer_return + if r1 + r0 = r1 + else + r2 = _nt_function_prototype_standard + if r2 + r0 = r2 + else + self.index = i0 + r0 = nil + end + end + + node_cache[:function_prototype][start_index] = r0 + + return r0 + end + + module FunctionPrototypeStandard0 + def return_type + elements[0] + end + + def name + elements[1] + end + + def argument_list + elements[2] + end + end + + def _nt_function_prototype_standard + start_index = index + if node_cache[:function_prototype_standard].has_key?(index) + cached = node_cache[:function_prototype_standard][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + r1 = _nt_return_type + s0 << r1 + if r1 + r2 = _nt_name + s0 << r2 + if r2 + r3 = _nt_argument_list + s0 << r3 + end + end + if s0.last + r0 = instantiate_node(FunctionPrototypeStandardNode,input, i0...index, s0) + r0.extend(FunctionPrototypeStandard0) + else + self.index = i0 + r0 = nil + end + + node_cache[:function_prototype_standard][start_index] = r0 + + return r0 + end + + module FunctionPrototypeFunctionPointerReturn0 + def return_type + elements[0] + end + + def left_paren + elements[1] + end + + def asterisk + elements[2] + end + + def name + elements[3] + end + + def function_arglist + elements[4] + end + + def right_paren + elements[5] + end + + def function_return_arglist + elements[6] + end + end + + def _nt_function_prototype_function_pointer_return + start_index = index + if node_cache[:function_prototype_function_pointer_return].has_key?(index) + cached = node_cache[:function_prototype_function_pointer_return][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + r1 = _nt_return_type + s0 << r1 + if r1 + r2 = _nt_left_paren + s0 << r2 + if r2 + r3 = _nt_asterisk + s0 << r3 + if r3 + r4 = _nt_name + s0 << r4 + if r4 + r5 = _nt_argument_list + s0 << r5 + if r5 + r6 = _nt_right_paren + s0 << r6 + if r6 + r7 = _nt_argument_list + s0 << r7 + end + end + end + end + end + end + if s0.last + r0 = instantiate_node(FunctionPrototypeFunctionPointerReturnNode,input, i0...index, s0) + r0.extend(FunctionPrototypeFunctionPointerReturn0) + else + self.index = i0 + r0 = nil + end + + node_cache[:function_prototype_function_pointer_return][start_index] = r0 + + return r0 + end + + def _nt_return_type + start_index = index + if node_cache[:return_type].has_key?(index) + cached = node_cache[:return_type][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + r1 = _nt_void + if r1 + r0 = r1 + else + r2 = _nt_type + if r2 + r0 = r2 + else + self.index = i0 + r0 = nil + end + end + + node_cache[:return_type][start_index] = r0 + + return r0 + end + + module ArgumentList0 + def argument + elements[0] + end + + end + + module ArgumentList1 + def left_paren + elements[0] + end + + def arguments + elements[1] + end + + def right_paren + elements[2] + end + end + + def _nt_argument_list + start_index = index + if node_cache[:argument_list].has_key?(index) + cached = node_cache[:argument_list][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + r1 = _nt_left_paren + s0 << r1 + if r1 + s2, i2 = [], index + loop do + i3, s3 = index, [] + r4 = _nt_argument + s3 << r4 + if r4 + r6 = _nt_comma + if r6 + r5 = r6 + else + r5 = instantiate_node(SyntaxNode,input, index...index) + end + s3 << r5 + end + if s3.last + r3 = instantiate_node(SyntaxNode,input, i3...index, s3) + r3.extend(ArgumentList0) + else + self.index = i3 + r3 = nil + end + if r3 + s2 << r3 + else + break + end + end + r2 = instantiate_node(SyntaxNode,input, i2...index, s2) + s0 << r2 + if r2 + r7 = _nt_right_paren + s0 << r7 + end + end + if s0.last + r0 = instantiate_node(ArgumentListNode,input, i0...index, s0) + r0.extend(ArgumentList1) + else + self.index = i0 + r0 = nil + end + + node_cache[:argument_list][start_index] = r0 + + return r0 + end + + def _nt_argument + start_index = index + if node_cache[:argument].has_key?(index) + cached = node_cache[:argument][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + r1 = _nt_func_ptr_prototype + if r1 + r0 = r1 + else + r2 = _nt_void + if r2 + r0 = r2 + else + r3 = _nt_type_and_name + if r3 + r0 = r3 + else + r4 = _nt_variable_argument + if r4 + r0 = r4 + else + self.index = i0 + r0 = nil + end + end + end + end + + node_cache[:argument][start_index] = r0 + + return r0 + end + + module VariableArgument0 + def space + elements[1] + end + end + + def _nt_variable_argument + start_index = index + if node_cache[:variable_argument].has_key?(index) + cached = node_cache[:variable_argument][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('...', index) == index + r1 = instantiate_node(SyntaxNode,input, index...(index + 3)) + @index += 3 + else + terminal_parse_failure('...') + r1 = nil + end + s0 << r1 + if r1 + r2 = _nt_space + s0 << r2 + end + if s0.last + r0 = instantiate_node(VarArgNode,input, i0...index, s0) + r0.extend(VariableArgument0) + else + self.index = i0 + r0 = nil + end + + node_cache[:variable_argument][start_index] = r0 + + return r0 + end + + module FuncPtrPrototype0 + def return_type + elements[0] + end + + def left_paren + elements[1] + end + + def asterisk + elements[2] + end + + def name + elements[3] + end + + def right_paren + elements[4] + end + + def argument_list + elements[5] + end + end + + def _nt_func_ptr_prototype + start_index = index + if node_cache[:func_ptr_prototype].has_key?(index) + cached = node_cache[:func_ptr_prototype][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + r1 = _nt_return_type + s0 << r1 + if r1 + r2 = _nt_left_paren + s0 << r2 + if r2 + r3 = _nt_asterisk + s0 << r3 + if r3 + r5 = _nt_name + if r5 + r4 = r5 + else + r4 = instantiate_node(SyntaxNode,input, index...index) + end + s0 << r4 + if r4 + r6 = _nt_right_paren + s0 << r6 + if r6 + r7 = _nt_argument_list + s0 << r7 + end + end + end + end + end + if s0.last + r0 = instantiate_node(FunctionPointerNode,input, i0...index, s0) + r0.extend(FuncPtrPrototype0) + else + self.index = i0 + r0 = nil + end + + node_cache[:func_ptr_prototype][start_index] = r0 + + return r0 + end + + module TypeAndName0 + def type + elements[0] + end + + def name + elements[1] + end + + end + + def _nt_type_and_name + start_index = index + if node_cache[:type_and_name].has_key?(index) + cached = node_cache[:type_and_name][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + r1 = _nt_type + s0 << r1 + if r1 + r3 = _nt_name + if r3 + r2 = r3 + else + r2 = instantiate_node(SyntaxNode,input, index...index) + end + s0 << r2 + if r2 + i4 = index + i5 = index + r6 = _nt_comma + if r6 + r5 = r6 + else + r7 = _nt_left_paren + if r7 + r5 = r7 + else + r8 = _nt_right_paren + if r8 + r5 = r8 + else + self.index = i5 + r5 = nil + end + end + end + if r5 + self.index = i4 + r4 = instantiate_node(SyntaxNode,input, index...index) + else + r4 = nil + end + s0 << r4 + end + end + if s0.last + r0 = instantiate_node(TypeWithNameNode,input, i0...index, s0) + r0.extend(TypeAndName0) + else + self.index = i0 + r0 = nil + end + + node_cache[:type_and_name][start_index] = r0 + + return r0 + end + + module Type0 + def space + elements[1] + end + end + + module Type1 + end + + def _nt_type + start_index = index + if node_cache[:type].has_key?(index) + cached = node_cache[:type][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + r2 = _nt_const + if r2 + r1 = r2 + else + r1 = instantiate_node(SyntaxNode,input, index...index) + end + s0 << r1 + if r1 + i3 = index + s4, i4 = [], index + loop do + i5, s5 = index, [] + i6 = index + if input.index('void', index) == index + r7 = instantiate_node(SyntaxNode,input, index...(index + 4)) + @index += 4 + else + terminal_parse_failure('void') + r7 = nil + end + if r7 + r6 = r7 + else + if input.index('unsigned', index) == index + r8 = instantiate_node(SyntaxNode,input, index...(index + 8)) + @index += 8 + else + terminal_parse_failure('unsigned') + r8 = nil + end + if r8 + r6 = r8 + else + if input.index('signed', index) == index + r9 = instantiate_node(SyntaxNode,input, index...(index + 6)) + @index += 6 + else + terminal_parse_failure('signed') + r9 = nil + end + if r9 + r6 = r9 + else + if input.index('long', index) == index + r10 = instantiate_node(SyntaxNode,input, index...(index + 4)) + @index += 4 + else + terminal_parse_failure('long') + r10 = nil + end + if r10 + r6 = r10 + else + if input.index('int', index) == index + r11 = instantiate_node(SyntaxNode,input, index...(index + 3)) + @index += 3 + else + terminal_parse_failure('int') + r11 = nil + end + if r11 + r6 = r11 + else + if input.index('short', index) == index + r12 = instantiate_node(SyntaxNode,input, index...(index + 5)) + @index += 5 + else + terminal_parse_failure('short') + r12 = nil + end + if r12 + r6 = r12 + else + if input.index('char', index) == index + r13 = instantiate_node(SyntaxNode,input, index...(index + 4)) + @index += 4 + else + terminal_parse_failure('char') + r13 = nil + end + if r13 + r6 = r13 + else + if input.index('float', index) == index + r14 = instantiate_node(SyntaxNode,input, index...(index + 5)) + @index += 5 + else + terminal_parse_failure('float') + r14 = nil + end + if r14 + r6 = r14 + else + if input.index('double', index) == index + r15 = instantiate_node(SyntaxNode,input, index...(index + 6)) + @index += 6 + else + terminal_parse_failure('double') + r15 = nil + end + if r15 + r6 = r15 + else + self.index = i6 + r6 = nil + end + end + end + end + end + end + end + end + end + s5 << r6 + if r6 + r16 = _nt_space + s5 << r16 + end + if s5.last + r5 = instantiate_node(SyntaxNode,input, i5...index, s5) + r5.extend(Type0) + else + self.index = i5 + r5 = nil + end + if r5 + s4 << r5 + else + break + end + end + if s4.empty? + self.index = i4 + r4 = nil + else + r4 = instantiate_node(SyntaxNode,input, i4...index, s4) + end + if r4 + r3 = r4 + else + r17 = _nt_name + if r17 + r3 = r17 + else + self.index = i3 + r3 = nil + end + end + s0 << r3 + if r3 + s18, i18 = [], index + loop do + r19 = _nt_asterisk + if r19 + s18 << r19 + else + break + end + end + r18 = instantiate_node(SyntaxNode,input, i18...index, s18) + s0 << r18 + if r18 + r21 = _nt_const + if r21 + r20 = r21 + else + r20 = instantiate_node(SyntaxNode,input, index...index) + end + s0 << r20 + end + end + end + if s0.last + r0 = instantiate_node(TypeNode,input, i0...index, s0) + r0.extend(Type1) + else + self.index = i0 + r0 = nil + end + + node_cache[:type][start_index] = r0 + + return r0 + end + + module Name0 + def space + elements[1] + end + end + + def _nt_name + start_index = index + if node_cache[:name].has_key?(index) + cached = node_cache[:name][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + s1, i1 = [], index + loop do + if input.index(Regexp.new('[a-zA-Z0-9_]'), index) == index + r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) + @index += 1 + else + r2 = nil + end + if r2 + s1 << r2 + else + break + end + end + if s1.empty? + self.index = i1 + r1 = nil + else + r1 = instantiate_node(SyntaxNode,input, i1...index, s1) + end + s0 << r1 + if r1 + r3 = _nt_space + s0 << r3 + end + if s0.last + r0 = instantiate_node(NameNode,input, i0...index, s0) + r0.extend(Name0) + else + self.index = i0 + r0 = nil + end + + node_cache[:name][start_index] = r0 + + return r0 + end + + module Void0 + def space + elements[1] + end + + end + + def _nt_void + start_index = index + if node_cache[:void].has_key?(index) + cached = node_cache[:void][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('void', index) == index + r1 = instantiate_node(SyntaxNode,input, index...(index + 4)) + @index += 4 + else + terminal_parse_failure('void') + r1 = nil + end + s0 << r1 + if r1 + r2 = _nt_space + s0 << r2 + if r2 + i3 = index + r4 = _nt_asterisk + if r4 + r3 = nil + else + self.index = i3 + r3 = instantiate_node(SyntaxNode,input, index...index) + end + s0 << r3 + end + end + if s0.last + r0 = instantiate_node(VoidNode,input, i0...index, s0) + r0.extend(Void0) + else + self.index = i0 + r0 = nil + end + + node_cache[:void][start_index] = r0 + + return r0 + end + + module Const0 + def space + elements[1] + end + end + + def _nt_const + start_index = index + if node_cache[:const].has_key?(index) + cached = node_cache[:const][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('const', index) == index + r1 = instantiate_node(SyntaxNode,input, index...(index + 5)) + @index += 5 + else + terminal_parse_failure('const') + r1 = nil + end + s0 << r1 + if r1 + r2 = _nt_space + s0 << r2 + end + if s0.last + r0 = instantiate_node(SyntaxNode,input, i0...index, s0) + r0.extend(Const0) + else + self.index = i0 + r0 = nil + end + + node_cache[:const][start_index] = r0 + + return r0 + end + + module Asterisk0 + def space + elements[1] + end + end + + def _nt_asterisk + start_index = index + if node_cache[:asterisk].has_key?(index) + cached = node_cache[:asterisk][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('*', index) == index + r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('*') + r1 = nil + end + s0 << r1 + if r1 + r2 = _nt_space + s0 << r2 + end + if s0.last + r0 = instantiate_node(SyntaxNode,input, i0...index, s0) + r0.extend(Asterisk0) + else + self.index = i0 + r0 = nil + end + + node_cache[:asterisk][start_index] = r0 + + return r0 + end + + module LeftParen0 + def space + elements[1] + end + end + + def _nt_left_paren + start_index = index + if node_cache[:left_paren].has_key?(index) + cached = node_cache[:left_paren][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('(', index) == index + r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('(') + r1 = nil + end + s0 << r1 + if r1 + r2 = _nt_space + s0 << r2 + end + if s0.last + r0 = instantiate_node(SyntaxNode,input, i0...index, s0) + r0.extend(LeftParen0) + else + self.index = i0 + r0 = nil + end + + node_cache[:left_paren][start_index] = r0 + + return r0 + end + + module RightParen0 + def space + elements[1] + end + end + + def _nt_right_paren + start_index = index + if node_cache[:right_paren].has_key?(index) + cached = node_cache[:right_paren][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index(')', index) == index + r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure(')') + r1 = nil + end + s0 << r1 + if r1 + r2 = _nt_space + s0 << r2 + end + if s0.last + r0 = instantiate_node(SyntaxNode,input, i0...index, s0) + r0.extend(RightParen0) + else + self.index = i0 + r0 = nil + end + + node_cache[:right_paren][start_index] = r0 + + return r0 + end + + module Comma0 + def space + elements[1] + end + end + + def _nt_comma + start_index = index + if node_cache[:comma].has_key?(index) + cached = node_cache[:comma][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index(',', index) == index + r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure(',') + r1 = nil + end + s0 << r1 + if r1 + r2 = _nt_space + s0 << r2 + end + if s0.last + r0 = instantiate_node(SyntaxNode,input, i0...index, s0) + r0.extend(Comma0) + else + self.index = i0 + r0 = nil + end + + node_cache[:comma][start_index] = r0 + + return r0 + end + + def _nt_space + start_index = index + if node_cache[:space].has_key?(index) + cached = node_cache[:space][index] + @index = cached.interval.end if cached + return cached + end + + s0, i0 = [], index + loop do + if input.index(' ', index) == index + r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure(' ') + r1 = nil + end + if r1 + s0 << r1 + else + break + end + end + r0 = instantiate_node(SyntaxNode,input, i0...index, s0) + + node_cache[:space][start_index] = r0 + + return r0 + end + +end + +class CMockFunctionPrototypeParser < Treetop::Runtime::CompiledParser + include CMockFunctionPrototype +end + diff --git a/lib/cmock_function_prototype_parser.treetop b/lib/cmock_function_prototype_parser.treetop new file mode 100644 index 0000000..e5c03d3 --- /dev/null +++ b/lib/cmock_function_prototype_parser.treetop @@ -0,0 +1,87 @@ +grammar CMockFunctionPrototype + + rule function_prototype + function_prototype_function_pointer_return / function_prototype_standard + end + + rule function_prototype_standard + return_type name argument_list + end + + rule function_prototype_function_pointer_return + # ex. float (*GetPtr(const char opCode))(float, float) + return_type left_paren asterisk name function_arglist:argument_list right_paren function_return_arglist:argument_list + end + + rule return_type + void / type + end + + rule argument_list + # without a priori knowledge of all custom types (i.e. typedefs), the parser can only recognize + # a list of primitives followed by an optional name or a single custom type followed by an optional name. + # otherwise, there's no way to distinguish the last type in a list from a possibly non-existent argument name; + # the rules in the grammar enforce this idea to ensure the parser fails rather than do something wonky + left_paren arguments:( argument:argument (comma)? )* right_paren + end + + rule argument + func_ptr_prototype / void / type_and_name / variable_argument + end + + rule variable_argument + '...' space + end + + rule func_ptr_prototype + # ex. int (*funcPtr)(float, char, char) + # add name: tag to name? so we can always access it in programming even if blank. + return_type left_paren asterisk name:name? right_paren argument_list + end + + rule type_and_name + # add name: tag to name? so we can always access it in programming even if blank. + # tell parser that type and optional name will always be followed by ',' '(' or ')' but don't consume them; + # this helps enforce the limits on what can be parsed in argument lists + type name:name? &( comma / left_paren / right_paren ) + end + + rule type + const? ((('void' / 'unsigned' / 'signed' / 'long' / 'int' / 'short' / 'char' / 'float' / 'double') space)+ / name) (asterisk)* const? + end + + rule name + [a-zA-Z0-9_]+ space + end + + rule void + # in reality, 'void' is something different than the 'void*' type so limit to 'void' here and handle 'void*' in type rule; + # recognizing the VoidNode uniquely in programming is helpful + 'void' space !asterisk + end + + rule const + 'const' space + end + + rule asterisk + '*' space + end + + rule left_paren + '(' space + end + + rule right_paren + ')' space + end + + rule comma + ',' space + end + + rule space + ' '* + end + +end diff --git a/rakefile.rb b/rakefile.rb index 5261465..5b9a8ec 100644 --- a/rakefile.rb +++ b/rakefile.rb @@ -23,9 +23,24 @@ task :config, :config_file do |t, args| configure_toolchain(args[:config_file]) end +desc "Generate parser(s) from Treetop grammar(s)" +task :treetop do + require 'rubygems' + require 'treetop' + + treetop_files = FileList.new('lib/*.treetop') + compiler = Treetop::Compiler::GrammarCompiler.new + + treetop_files.each do |file| + compiler.compile(file) + end + + #`vendor/gems/treetop-1.2.5/bin/tt lib/cmock_function_prototype_parser.treetop` +end + namespace :test do - desc "Run CMock and example application tests" + desc "Run all unit and system tests" task :all => ['test:units', 'test:system'] Rake::TestTask.new('units') do |t| diff --git a/test/unit/cmock_config_test.rb b/test/unit/cmock_config_test.rb index 90b853a..c98cb35 100644 --- a/test/unit/cmock_config_test.rb +++ b/test/unit/cmock_config_test.rb @@ -1,5 +1,5 @@ require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" -require File.expand_path(File.dirname(__FILE__)) + "/../../lib/cmock_config" +require 'cmock_config' class CMockConfigTest < Test::Unit::TestCase def setup diff --git a/test/unit/cmock_file_writer_test.rb b/test/unit/cmock_file_writer_test.rb index 99b3635..532b9ef 100644 --- a/test/unit/cmock_file_writer_test.rb +++ b/test/unit/cmock_file_writer_test.rb @@ -1,5 +1,5 @@ require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" -require File.expand_path(File.dirname(__FILE__)) + "/../../lib/cmock_file_writer" +require 'cmock_file_writer' class CMockFileWriterTest < Test::Unit::TestCase def setup diff --git a/test/unit/cmock_function_prototype_parser_test.rb b/test/unit/cmock_function_prototype_parser_test.rb new file mode 100644 index 0000000..cfd99d9 --- /dev/null +++ b/test/unit/cmock_function_prototype_parser_test.rb @@ -0,0 +1,264 @@ +require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" + +require 'rubygems' +require 'treetop' +require 'cmock_function_prototype_node_classes' +require 'cmock_function_prototype_parser' + + +class CMockFunctionPrototypeParserTest < Test::Unit::TestCase + + def setup + @parser = CMockFunctionPrototypeParser.new + end + + def teardown + end + + should "parse simple void function prototypes" do + parsed = @parser.parse("void foo_bar(void)") + + assert_equal('void foo_bar(void)', parsed.get_declaration) + assert_equal('void', parsed.get_return_type) + assert_equal('foo_bar', parsed.get_function_name) + assert_equal('void', parsed.get_argument_list) + assert_equal([], parsed.get_arguments) + assert_nil(parsed.get_var_arg) + + parsed = @parser.parse("void foo_bar()") + + assert_equal('void foo_bar(void)', parsed.get_declaration) + assert_equal('void', parsed.get_return_type) + assert_equal('foo_bar', parsed.get_function_name) + assert_equal('void', parsed.get_argument_list) + assert_equal([], parsed.get_arguments) + assert_nil(parsed.get_var_arg) + end + + should "fail to parse garbage, broken function prototypes, and strings that only appear to be prototypes" do + assert_nil(@parser.parse("** !")) + assert_nil(@parser.parse("ashjfhskdh")) + + assert_nil(@parser.parse("void")) # no function name or argument list + assert_nil(@parser.parse("void foo-bar(void)")) # illegal function name + assert_nil(@parser.parse("void foo_bar")) # no param list + assert_nil(@parser.parse("foo_bar(void)")) # no return type + assert_nil(@parser.parse("void foo_bar(int (func)(int a, char b), void (*)(void))")) # no asterisk in function pointer definition + assert_nil(@parser.parse("unsigned int * (*(double foo, THING bar))(unsigned int a)")) # no function name + assert_nil(@parser.parse("unsigned int * (* func(double foo, THING bar))")) # no parameter list for function pointer return + + assert_nil(@parser.parse("typedef void (*FUNCPTR)(void)")) # typedef string that looks like function prototype + assert_nil(@parser.parse("(parenthetical comment)")) + end + + should "parse and normalize white space" do + parsed = @parser.parse("void foo_bar ( void )") + assert_equal("void foo_bar(void)", parsed.get_declaration) + + parsed = @parser.parse("void foo_bar( int a,int b)") + assert_equal("void foo_bar( int a, int b )", parsed.get_declaration) + + parsed = @parser.parse("void foo_bar( int a, int b, int , unsigned int d)") + assert_equal("void foo_bar( int a, int b, int, unsigned int d )", parsed.get_declaration) + + parsed = @parser.parse("unsigned int foo_bar(unsigned char * const )") + assert_equal("unsigned int foo_bar( unsigned char* const )", parsed.get_declaration) + + parsed = @parser.parse("int foo_bar(const unsigned char * * ptr )") + assert_equal("int foo_bar( const unsigned char** ptr )", parsed.get_declaration) + + parsed = @parser.parse("void foo_bar ( int (* function) (int, char ), void ( * ) (void ) )") + assert_equal("void foo_bar( int (*function)( int, char ), void (*)(void) )", parsed.get_declaration) + + parsed = @parser.parse("float ( * GetPtr( const char opCode))( float, float)") + assert_equal("float (*GetPtr( const char opCode ))( float, float )", parsed.get_declaration) + end + + should "parse out simple arguments from an argument list into an array of hashes" do + # function pointers & var args tested elsewhere + + # void is a special argument that yields no params to mock + parsed = @parser.parse("void foo_bar(void)") + assert_equal('void', parsed.get_argument_list) + assert_equal([], parsed.get_arguments) + + parsed = @parser.parse("void foo_bar(int a, unsigned int b)") + assert_equal('int a, unsigned int b', parsed.get_argument_list) + assert_equal([ + {:type => 'int', :name => 'a'}, + {:type => 'unsigned int', :name => 'b'}], + parsed.get_arguments) + assert_nil(parsed.get_var_arg) + + parsed = @parser.parse("void foo_bar(int a, unsigned int b)") + assert_equal('int a, unsigned int b', parsed.get_argument_list) + assert_equal([ + {:type => 'int', :name => 'a'}, + {:type => 'unsigned int', :name => 'b'}], + parsed.get_arguments) + assert_nil(parsed.get_var_arg) + + parsed = @parser.parse("void foo_bar(unsigned char * abc, const unsigned long int xyz_123)") + assert_equal('unsigned char* abc, const unsigned long int xyz_123', parsed.get_argument_list) + assert_equal([ + {:type => 'unsigned char*', :name => 'abc'}, + {:type => 'const unsigned long int', :name => 'xyz_123'}], + parsed.get_arguments) + assert_nil(parsed.get_var_arg) + + parsed = @parser.parse("void foo_bar(CUSTOM_TYPE abc, CUSTOM_TYPE* xyz_123)") + assert_equal('CUSTOM_TYPE abc, CUSTOM_TYPE* xyz_123', parsed.get_argument_list) + assert_equal([ + {:type => 'CUSTOM_TYPE', :name => 'abc'}, + {:type => 'CUSTOM_TYPE*', :name => 'xyz_123'}], + parsed.get_arguments) + assert_nil(parsed.get_var_arg) + end + + should "fail to parse arguments that mix multiple custom types or a custom type and a primitive" do + # parser can only recognize strings of primitves followed by optional name or + # a single custom type followed by optional name; + # without knowing custom types a priori there's no way to parse all possible combinations + assert_nil(@parser.parse("void foo_bar(unsigned CUSTOM_TYPE abc)")) + assert_nil(@parser.parse("void foo_bar(CUSTOM_TYPE1 CUSTOM_TYPE2 abc)")) + assert_nil(@parser.parse("void foo_bar(CUSTOM_TYPE, CUSTOM_TYPE1 CUSTOM_TYPE2 abc)")) + assert_nil(@parser.parse("void foo_bar(CUSTOM_TYPE1 CUSTOM_TYPE2 abc, CUSTOM_TYPE1 CUSTOM_TYPE2 xyz)")) + end + + should "parse out simple return types" do + # function pointers tested elsewhere + + parsed = @parser.parse("void foo_bar(void)") + assert_equal('void', parsed.get_return_type) + + parsed = @parser.parse("void * foo_bar(void)") + assert_equal('void*', parsed.get_return_type) + + parsed = @parser.parse("unsigned int foo_bar(void)") + assert_equal('unsigned int', parsed.get_return_type) + + parsed = @parser.parse("unsigned long int foo_bar(void)") + assert_equal('unsigned long int', parsed.get_return_type) + + parsed = @parser.parse("CUSTOM_TYPE foo_bar(void)") + assert_equal('CUSTOM_TYPE', parsed.get_return_type) + end + + should "normalize pointer notation" do + parsed = @parser.parse("void * foo(unsigned int * a, char * *b, int* c, int (* func)(void))") + + assert_equal('void*', parsed.get_return_type) + assert_equal('unsigned int* a, char** b, int* c, int (*func)(void)', parsed.get_argument_list) + assert_equal([ + {:type => 'unsigned int*', :name => 'a'}, + {:type => 'char**', :name => 'b'}, + {:type => 'int*', :name => 'c'}, + {:type => 'int (*)(void)', :name => 'func'}], + parsed.get_arguments) + assert_nil(parsed.get_var_arg) + end + + should "specially process var args in preparation for mocking" do + parsed = @parser.parse("void foo_bar(...)") + assert_equal('void', parsed.get_argument_list) + assert_equal([], parsed.get_arguments) + assert_equal('...', parsed.get_var_arg) + + parsed = @parser.parse("void foo_bar(int a, ...)") + assert_equal('int a', parsed.get_argument_list) + assert_equal( + [{:type => 'int', :name => 'a'}], + parsed.get_arguments) + assert_equal('...', parsed.get_var_arg) + + parsed = @parser.parse("void thing(void (*func)(int, ...))") + assert_equal('void (*func)( int, ... )', parsed.get_argument_list) + assert_equal( + [{:type => 'void (*)( int, ... )', :name => 'func'}], + parsed.get_arguments) + assert_nil(parsed.get_var_arg) # no var args for thing(), just for the function pointer param + end + + should "parse prototypes handling function pointers" do + # function pointer prototypes in argument lists (i.e. no typedef) + parsed = @parser.parse("void thing(int (*func_ptr)(int, int))") + assert_equal('int (*func_ptr)( int, int )', parsed.get_argument_list) + assert_equal( + [{:type => 'int (*)( int, int )', :name => 'func_ptr'}], + parsed.get_arguments) + + parsed = @parser.parse("void foo_bar(void * (*func)(int *, unsigned long int, ...))") + assert_equal('void* (*func)( int*, unsigned long int, ... )', parsed.get_argument_list) + assert_equal( + [{:type => 'void* (*)( int*, unsigned long int, ... )', :name => 'func'}], + parsed.get_arguments) + + parsed = @parser.parse("void foo_bar(int (* func1)(int a, char b), void (*func2)(void))") + assert_equal('int (*func1)( int a, char b ), void (*func2)(void)', parsed.get_argument_list) + assert_equal( + [{:type => 'int (*)( int a, char b )', :name => 'func1'}, + {:type => 'void (*)(void)', :name => 'func2'}], + parsed.get_arguments) + + # directly returning function pointers (i.e. no typedef) + parsed = @parser.parse("float (*func(const char opCode))(float, float)") + assert_equal('float (*)( float, float )', parsed.get_return_type) + + parsed = @parser.parse("void (*func (void))(void)") + assert_equal('void (*)(void)', parsed.get_return_type) + + parsed = @parser.parse("unsigned int * (* func(double foo, THING bar))(unsigned int a)") + assert_equal('unsigned int* (*)( unsigned int a )', parsed.get_return_type) + end + + should "create unique typedefs for function pointer prototypes in argument lists and return types" do + # function prototype argument list handling + parsed = @parser.parse("void foo_bar(unsigned int a, void (*func)(int *, unsigned long int, ...))") + assert_equal( + [{:type => 'void (*)( int*, unsigned long int, ... )', + :typename => 'FUNC_PTR_FOO_BAR_PARAM_2_T', + :typedef => 'typedef void (*FUNC_PTR_FOO_BAR_PARAM_2_T)( int*, unsigned long int, ... );'}], + parsed.get_typedefs) + + parsed = @parser.parse("void test_func(void (*)(int, char), unsigned int (*)(void))") + assert_equal( + [{:type => 'void (*)( int, char )', + :typename => 'FUNC_PTR_TEST_FUNC_PARAM_1_T', + :typedef => 'typedef void (*FUNC_PTR_TEST_FUNC_PARAM_1_T)( int, char );'}, + {:type => 'unsigned int (*)(void)', + :typename => 'FUNC_PTR_TEST_FUNC_PARAM_2_T', + :typedef => 'typedef unsigned int (*FUNC_PTR_TEST_FUNC_PARAM_2_T)(void);'}], + parsed.get_typedefs) + + # function prototype return type handling + parsed = @parser.parse("void (*func (void))(void)") + assert_equal( + [{:type => 'void (*)(void)', + :typename => 'FUNC_PTR_FUNC_RETURN_T', + :typedef => 'typedef void (*FUNC_PTR_FUNC_RETURN_T)(void);'}], + parsed.get_typedefs) + + parsed = @parser.parse("unsigned int * (* func(double foo, THING bar))(unsigned int, ...)") + assert_equal( + [{:type => 'unsigned int* (*)( unsigned int, ... )', + :typename => 'FUNC_PTR_FUNC_RETURN_T', + :typedef => 'typedef unsigned int* (*FUNC_PTR_FUNC_RETURN_T)( unsigned int, ... );'}], + parsed.get_typedefs) + end + + should "insert unique names for top-level nameless arguments" do + parsed = @parser.parse("void foo_bar(int (*)(int, int), char, unsigned int c, CUSTOM_THING)") + + assert_equal('int (*cmock_arg1)( int, int ), char cmock_arg2, unsigned int c, CUSTOM_THING cmock_arg4', parsed.get_argument_list) + assert_equal( + [{:type => 'int (*)( int, int )', :name => 'cmock_arg1'}, + {:type => 'char', :name => 'cmock_arg2'}, + {:type => 'unsigned int', :name => 'c'}, + {:type => 'CUSTOM_THING', :name => 'cmock_arg4'}], + parsed.get_arguments) + assert_nil(parsed.get_var_arg) + end + + +end + diff --git a/test/unit/cmock_generator_main_test.rb b/test/unit/cmock_generator_main_test.rb index c67e228..d8940d0 100644 --- a/test/unit/cmock_generator_main_test.rb +++ b/test/unit/cmock_generator_main_test.rb @@ -2,7 +2,7 @@ $ThisIsOnlyATest = true require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" -require File.expand_path(File.dirname(__FILE__)) + "/../../lib/cmock_generator" +require 'cmock_generator' class MockedPluginHelper def initialize return_this diff --git a/test/unit/cmock_generator_plugin_cexception_test.rb b/test/unit/cmock_generator_plugin_cexception_test.rb index 5065323..312c44d 100644 --- a/test/unit/cmock_generator_plugin_cexception_test.rb +++ b/test/unit/cmock_generator_plugin_cexception_test.rb @@ -1,5 +1,5 @@ require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" -require File.expand_path(File.dirname(__FILE__)) + "/../../lib/cmock_generator_plugin_cexception" +require 'cmock_generator_plugin_cexception' class CMockGeneratorPluginCExceptionTest < Test::Unit::TestCase def setup diff --git a/test/unit/cmock_generator_plugin_expect_test.rb b/test/unit/cmock_generator_plugin_expect_test.rb index 2477d50..9267e45 100644 --- a/test/unit/cmock_generator_plugin_expect_test.rb +++ b/test/unit/cmock_generator_plugin_expect_test.rb @@ -1,5 +1,5 @@ require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" -require File.expand_path(File.dirname(__FILE__)) + "/../../lib/cmock_generator_plugin_expect" +require 'cmock_generator_plugin_expect' class CMockGeneratorPluginExpectTest < Test::Unit::TestCase def setup diff --git a/test/unit/cmock_generator_plugin_ignore_test.rb b/test/unit/cmock_generator_plugin_ignore_test.rb index a55f46c..ac042d6 100644 --- a/test/unit/cmock_generator_plugin_ignore_test.rb +++ b/test/unit/cmock_generator_plugin_ignore_test.rb @@ -1,5 +1,5 @@ require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" -require File.expand_path(File.dirname(__FILE__)) + "/../../lib/cmock_generator_plugin_ignore" +require 'cmock_generator_plugin_ignore' class CMockGeneratorPluginIgnoreTest < Test::Unit::TestCase def setup diff --git a/test/unit/cmock_generator_utils_test.rb b/test/unit/cmock_generator_utils_test.rb index 2267aff..32b9602 100644 --- a/test/unit/cmock_generator_utils_test.rb +++ b/test/unit/cmock_generator_utils_test.rb @@ -1,5 +1,5 @@ require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" -require File.expand_path(File.dirname(__FILE__)) + "/../../lib/cmock_generator_utils" +require 'cmock_generator_utils' class CMockGeneratorUtilsTest < Test::Unit::TestCase def setup @@ -139,7 +139,8 @@ class CMockGeneratorUtilsTest < Test::Unit::TestCase expected = [" Mock.Nectarine_CallsExpected++;\n"] returned = @cmock_generator_utils.code_add_base_expectation("Nectarine") - assert_equal(expected, returned) end + assert_equal(expected, returned) + end should "add base expectations, with stuff for strict ordering turned on" do expected = [" Mock.Nectarine_CallsExpected++;\n", diff --git a/test/unit/cmock_header_parser_test.rb b/test/unit/cmock_header_parser_test.rb index 976ed3e..09c0e90 100644 --- a/test/unit/cmock_header_parser_test.rb +++ b/test/unit/cmock_header_parser_test.rb @@ -1,5 +1,5 @@ require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" -require File.expand_path(File.dirname(__FILE__)) + "/../../lib/cmock_header_parser" +require 'cmock_header_parser' class CMockHeaderParserTest < Test::Unit::TestCase @@ -116,7 +116,7 @@ class CMockHeaderParserTest < Test::Unit::TestCase source = "typedef void SILLY_VOID_TYPE1;\n" + "typedef void SILLY_VOID_TYPE2 ;\n" + - "typedef void (*FUNCPTR)(void);\n\n" + # do no substitution on type + "typedef void (*FUNCPTR)(void);\n\n" + # don't get fooled by function pointer typedef with void as return type "SILLY_VOID_TYPE2 Foo(int a, unsigned int b);\n" + "void\n shiz(SILLY_VOID_TYPE1 *);\n" + "void tat(FUNCPTR);\n" diff --git a/test/unit/cmock_plugin_manager_test.rb b/test/unit/cmock_plugin_manager_test.rb index b4d8c0e..20486f6 100644 --- a/test/unit/cmock_plugin_manager_test.rb +++ b/test/unit/cmock_plugin_manager_test.rb @@ -1,5 +1,5 @@ require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" -require File.expand_path(File.dirname(__FILE__)) + "/../../lib/cmock_plugin_manager" +require 'cmock_plugin_manager' class CMockPluginManagerTest < Test::Unit::TestCase def setup diff --git a/test/unit/cmock_unityhelper_parser_test.rb b/test/unit/cmock_unityhelper_parser_test.rb index d6d8783..7e2bb8b 100644 --- a/test/unit/cmock_unityhelper_parser_test.rb +++ b/test/unit/cmock_unityhelper_parser_test.rb @@ -1,5 +1,5 @@ require File.expand_path(File.dirname(__FILE__)) + "/../test_helper" -require File.expand_path(File.dirname(__FILE__)) + "/../../lib/cmock_unityhelper_parser" +require 'cmock_unityhelper_parser' class CMockUnityHelperParserTest < Test::Unit::TestCase diff --git a/vendor/gems/polyglot-0.2.5/History.txt b/vendor/gems/polyglot-0.2.5/History.txt new file mode 100755 index 0000000..cb268e5 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/History.txt @@ -0,0 +1,36 @@ +== 0.2.5 2009-03-04 + +* 1 significant fix: + * Polyglot's require may be called with a Pathname, or other object allowed by Kernel#require that doesn't support [] (Kernel#require uses to_str apparently) + +== 0.2.4 2008-05-29 + +* 1 significant fix: + * Previous LoadError change is checked in this time (oops!) + +== 0.2.3 2008-05-29 + +* 2 minor enhancements: + * Raise MissingSourceFile exception instead of LoadError if ActiveSupport is loaded + * Re-raise original exception new one on require load fail + +== 0.2.2 2008-05-12 + +* 2 minor enhancements: + * Doesn't search $: when asked to load an absolute path + * Adds a helpful exception message on LoadError + +== 0.2.1 2008-03-05 + +* 1 minor defect: + * code to raise LoadError itself raised an exception + +== 0.2.0 2008-02-13 + +* 1 major enhancement: + * Doesn't reload on every require + +== 0.1.0 2007-10-22 + +* 1 major enhancement: + * Initial release diff --git a/vendor/gems/polyglot-0.2.5/License.txt b/vendor/gems/polyglot-0.2.5/License.txt new file mode 100755 index 0000000..659fbb3 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/License.txt @@ -0,0 +1,20 @@ +Copyright (c) 2007 Clifford Heath + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/gems/polyglot-0.2.5/Manifest.txt b/vendor/gems/polyglot-0.2.5/Manifest.txt new file mode 100755 index 0000000..158c081 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/Manifest.txt @@ -0,0 +1,24 @@ +History.txt +License.txt +Manifest.txt +README.txt +Rakefile +config/hoe.rb +config/requirements.rb +lib/polyglot.rb +lib/polyglot/version.rb +log/debug.log +script/destroy +script/generate +script/txt2html +setup.rb +tasks/deployment.rake +tasks/environment.rake +tasks/website.rake +test/test_helper.rb +test/test_polyglot.rb +website/index.html +website/index.txt +website/javascripts/rounded_corners_lite.inc.js +website/stylesheets/screen.css +website/template.rhtml diff --git a/vendor/gems/polyglot-0.2.5/README.txt b/vendor/gems/polyglot-0.2.5/README.txt new file mode 100755 index 0000000..a06db5b --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/README.txt @@ -0,0 +1,87 @@ += polyglot + +* http://polyglot.rubyforge.org + +== DESCRIPTION: + +Author: Clifford Heath, 2007 + +The Polyglot library allows a Ruby module to register a loader +for the file type associated with a filename extension, and it +augments 'require' to find and load matching files. + +This supports the creation of DSLs having a syntax that is most +appropriate to their purpose, instead of abusing the Ruby syntax. + +Files are sought using the normal Ruby search path. + +== EXAMPLE: + +In file rubyglot.rb, define and register a file type handler: + + require 'polyglot' + + class RubyglotLoader + def self.load(filename, options = nil, &block) + File.open(filename) {|file| + # Load the contents of file as Ruby code: + # Implement your parser here instead! + Kernel.eval(file.read) + } + end + end + + Polyglot.register("rgl", RubyglotLoader) + +In file test.rb: + + require 'rubyglot' # Create my file type handler + require 'hello' # Can add extra options or even a block here + puts "Ready to go" + Hello.new + +In file hello.rgl (this simple example uses Ruby code): + + puts "Initializing" + class Hello + def initialize() + puts "Hello, world\n" + end + end + +Run: + + $ ruby test.rb + Initializing + Ready to go + Hello, world + $ + +== INSTALL: + +sudo gem install polyglot + +== LICENSE: + +(The MIT License) + +Copyright (c) 2007 Clifford Heath + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/gems/polyglot-0.2.5/Rakefile b/vendor/gems/polyglot-0.2.5/Rakefile new file mode 100755 index 0000000..e469154 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/Rakefile @@ -0,0 +1,4 @@ +require 'config/requirements' +require 'config/hoe' # setup Hoe + all gem configuration + +Dir['tasks/**/*.rake'].each { |rake| load rake } \ No newline at end of file diff --git a/vendor/gems/polyglot-0.2.5/config/hoe.rb b/vendor/gems/polyglot-0.2.5/config/hoe.rb new file mode 100755 index 0000000..cf85a22 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/config/hoe.rb @@ -0,0 +1,71 @@ +require 'polyglot/version' + +AUTHOR = 'Clifford Heath' # can also be an array of Authors +EMAIL = "cjheath@rubyforge.org" +DESCRIPTION = "Allows custom language loaders for specified file extensions to be hooked into require" +GEM_NAME = 'polyglot' # what ppl will type to install your gem +RUBYFORGE_PROJECT = 'polyglot' # The unix name for your project +HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org" +DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}" + +@config_file = "~/.rubyforge/user-config.yml" +@config = nil +RUBYFORGE_USERNAME = "unknown" +def rubyforge_username + unless @config + begin + @config = YAML.load(File.read(File.expand_path(@config_file))) + rescue + puts <<-EOS +ERROR: No rubyforge config file found: #{@config_file} +Run 'rubyforge setup' to prepare your env for access to Rubyforge + - See http://newgem.rubyforge.org/rubyforge.html for more details + EOS + exit + end + end + RUBYFORGE_USERNAME.replace @config["username"] +end + + +REV = nil +# UNCOMMENT IF REQUIRED: +# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil +VERS = Polyglot::VERSION::STRING + (REV ? ".#{REV}" : "") +RDOC_OPTS = ['--quiet', '--title', 'polyglot documentation', + "--opname", "index.html", + "--line-numbers", + "--main", "README", + "--inline-source"] + +class Hoe + def extra_deps + @extra_deps.reject! { |x| Array(x).first == 'hoe' } + @extra_deps + end +end + +# Generate all the Rake tasks +# Run 'rake -T' to see list of generated tasks (from gem root directory) +hoe = Hoe.new(GEM_NAME, VERS) do |p| + p.author = AUTHOR + p.description = DESCRIPTION + p.email = EMAIL + p.summary = DESCRIPTION + p.url = HOMEPATH + p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT + p.test_globs = ["test/**/test_*.rb"] + p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean. + + # == Optional + p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n") + #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ] + + #p.spec_extras = {} # A hash of extra values to set in the gemspec. + +end + +CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\n\n") +PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}" +hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc') +hoe.rsync_args = '-av --delete --ignore-errors' diff --git a/vendor/gems/polyglot-0.2.5/config/requirements.rb b/vendor/gems/polyglot-0.2.5/config/requirements.rb new file mode 100755 index 0000000..081423f --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/config/requirements.rb @@ -0,0 +1,17 @@ +require 'fileutils' +include FileUtils + +require 'rubygems' +%w[rake hoe newgem rubigen].each do |req_gem| + begin + require req_gem + rescue LoadError + puts "This Rakefile requires the '#{req_gem}' RubyGem." + puts "Installation: gem install #{req_gem} -y" + exit + end +end + +$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib])) + +require 'polyglot' \ No newline at end of file diff --git a/vendor/gems/polyglot-0.2.5/lib/polyglot.rb b/vendor/gems/polyglot-0.2.5/lib/polyglot.rb new file mode 100755 index 0000000..2f96d24 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/lib/polyglot.rb @@ -0,0 +1,63 @@ +$:.unshift File.dirname(__FILE__) + +module Polyglot + @registrations ||= {} # Guard against reloading + @loaded ||= {} + + def self.register(extension, klass) + extension = [extension] unless Enumerable === extension + extension.each{|e| + @registrations[e] = klass + } + end + + def self.find(file, *options, &block) + extensions = @registrations.keys*"," + is_absolute = file[0] == File::SEPARATOR || file[0] == File::ALT_SEPARATOR || file =~ /\A[A-Z]:\\/i + (is_absolute ? [""] : $:).each{|lib| + base = is_absolute ? "" : lib+File::SEPARATOR + # In Windows, repeated SEPARATOR chars have a special meaning, avoid adding them + matches = Dir[base+file+".{"+extensions+"}"] + # Revisit: Should we do more do if more than one candidate found? + $stderr.puts "Polyglot: found more than one candidate for #{file}: #{matches*", "}" if matches.size > 1 + if path = matches[0] + return [ path, @registrations[path.gsub(/.*\./,'')]] + end + } + return nil + end + + def self.load(*a, &b) + file = a[0].to_str + return if @loaded[file] # Check for $: changes or file time changes and reload? + begin + source_file, loader = Polyglot.find(file, *a[1..-1], &b) + if (loader) + loader.load(source_file) + @loaded[file] = true + else + msg = "Failed to load #{file} using extensions #{(@registrations.keys+["rb"]).sort*", "}" + if defined?(MissingSourceFile) + raise MissingSourceFile.new(msg, file) + else + raise LoadError.new(msg) + end + end + end + end +end + +module Kernel + alias polyglot_original_require require + + def require(*a, &b) + polyglot_original_require(*a, &b) + rescue LoadError => load_error + begin + Polyglot.load(*a, &b) + rescue LoadError + # Raise the original exception, possibly a MissingSourceFile with a path + raise load_error + end + end +end diff --git a/vendor/gems/polyglot-0.2.5/lib/polyglot/version.rb b/vendor/gems/polyglot-0.2.5/lib/polyglot/version.rb new file mode 100755 index 0000000..9202a6e --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/lib/polyglot/version.rb @@ -0,0 +1,9 @@ +module Polyglot #:nodoc: + module VERSION #:nodoc: + MAJOR = 0 + MINOR = 2 + TINY = 5 + + STRING = [MAJOR, MINOR, TINY].join('.') + end +end diff --git a/vendor/gems/polyglot-0.2.5/log/debug.log b/vendor/gems/polyglot-0.2.5/log/debug.log new file mode 100755 index 0000000..e69de29 diff --git a/vendor/gems/polyglot-0.2.5/script/destroy b/vendor/gems/polyglot-0.2.5/script/destroy new file mode 100755 index 0000000..fe01698 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/script/destroy @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby +APP_ROOT = File.join(File.dirname(__FILE__), '..') + +begin + require 'rubigen' +rescue LoadError + require 'rubygems' + require 'rubigen' +end +require 'rubigen/scripts/destroy' + +ARGV.shift if ['--help', '-h'].include?(ARGV[0]) +RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme] +RubiGen::Scripts::Destroy.new.run(ARGV) diff --git a/vendor/gems/polyglot-0.2.5/script/generate b/vendor/gems/polyglot-0.2.5/script/generate new file mode 100755 index 0000000..692db9a --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/script/generate @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby +APP_ROOT = File.join(File.dirname(__FILE__), '..') + +begin + require 'rubigen' +rescue LoadError + require 'rubygems' + require 'rubigen' +end +require 'rubigen/scripts/generate' + +ARGV.shift if ['--help', '-h'].include?(ARGV[0]) +RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme] +RubiGen::Scripts::Generate.new.run(ARGV) diff --git a/vendor/gems/polyglot-0.2.5/script/txt2html b/vendor/gems/polyglot-0.2.5/script/txt2html new file mode 100755 index 0000000..9b3ae08 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/script/txt2html @@ -0,0 +1,74 @@ +#!/usr/bin/env ruby + +require 'rubygems' +begin + require 'newgem' +rescue LoadError + puts "\n\nGenerating the website requires the newgem RubyGem" + puts "Install: gem install newgem\n\n" + exit(1) +end +require 'redcloth' +require 'syntax/convertors/html' +require 'erb' +require File.dirname(__FILE__) + '/../lib/polyglot/version.rb' + +version = Polyglot::VERSION::STRING +download = 'http://rubyforge.org/projects/polyglot' + +class Fixnum + def ordinal + # teens + return 'th' if (10..19).include?(self % 100) + # others + case self % 10 + when 1: return 'st' + when 2: return 'nd' + when 3: return 'rd' + else return 'th' + end + end +end + +class Time + def pretty + return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}" + end +end + +def convert_syntax(syntax, source) + return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^
|
$!,'') +end + +if ARGV.length >= 1 + src, template = ARGV + template ||= File.join(File.dirname(__FILE__), '/../website/template.rhtml') + +else + puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html") + exit! +end + +template = ERB.new(File.open(template).read) + +title = nil +body = nil +File.open(src) do |fsrc| + title_text = fsrc.readline + body_text = fsrc.read + syntax_items = [] + body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)!m){ + ident = syntax_items.length + element, syntax, source = $1, $2, $3 + syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}" + "syntax-temp-#{ident}" + } + title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip + body = RedCloth.new(body_text).to_html + body.gsub!(%r!(?:
)?syntax-temp-(\d+)(?:
)?!){ syntax_items[$1.to_i] } +end +stat = File.stat(src) +created = stat.ctime +modified = stat.mtime + +$stdout << template.result(binding) diff --git a/vendor/gems/polyglot-0.2.5/setup.rb b/vendor/gems/polyglot-0.2.5/setup.rb new file mode 100755 index 0000000..424a5f3 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/setup.rb @@ -0,0 +1,1585 @@ +# +# setup.rb +# +# Copyright (c) 2000-2005 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the terms of +# the GNU LGPL, Lesser General Public License version 2.1. +# + +unless Enumerable.method_defined?(:map) # Ruby 1.4.6 + module Enumerable + alias map collect + end +end + +unless File.respond_to?(:read) # Ruby 1.6 + def File.read(fname) + open(fname) {|f| + return f.read + } + end +end + +unless Errno.const_defined?(:ENOTEMPTY) # Windows? + module Errno + class ENOTEMPTY + # We do not raise this exception, implementation is not needed. + end + end +end + +def File.binread(fname) + open(fname, 'rb') {|f| + return f.read + } +end + +# for corrupted Windows' stat(2) +def File.dir?(path) + File.directory?((path[-1,1] == '/') ? path : path + '/') +end + + +class ConfigTable + + include Enumerable + + def initialize(rbconfig) + @rbconfig = rbconfig + @items = [] + @table = {} + # options + @install_prefix = nil + @config_opt = nil + @verbose = true + @no_harm = false + end + + attr_accessor :install_prefix + attr_accessor :config_opt + + attr_writer :verbose + + def verbose? + @verbose + end + + attr_writer :no_harm + + def no_harm? + @no_harm + end + + def [](key) + lookup(key).resolve(self) + end + + def []=(key, val) + lookup(key).set val + end + + def names + @items.map {|i| i.name } + end + + def each(&block) + @items.each(&block) + end + + def key?(name) + @table.key?(name) + end + + def lookup(name) + @table[name] or setup_rb_error "no such config item: #{name}" + end + + def add(item) + @items.push item + @table[item.name] = item + end + + def remove(name) + item = lookup(name) + @items.delete_if {|i| i.name == name } + @table.delete_if {|name, i| i.name == name } + item + end + + def load_script(path, inst = nil) + if File.file?(path) + MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path + end + end + + def savefile + '.config' + end + + def load_savefile + begin + File.foreach(savefile()) do |line| + k, v = *line.split(/=/, 2) + self[k] = v.strip + end + rescue Errno::ENOENT + setup_rb_error $!.message + "\n#{File.basename($0)} config first" + end + end + + def save + @items.each {|i| i.value } + File.open(savefile(), 'w') {|f| + @items.each do |i| + f.printf "%s=%s\n", i.name, i.value if i.value? and i.value + end + } + end + + def load_standard_entries + standard_entries(@rbconfig).each do |ent| + add ent + end + end + + def standard_entries(rbconfig) + c = rbconfig + + rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) + + major = c['MAJOR'].to_i + minor = c['MINOR'].to_i + teeny = c['TEENY'].to_i + version = "#{major}.#{minor}" + + # ruby ver. >= 1.4.4? + newpath_p = ((major >= 2) or + ((major == 1) and + ((minor >= 5) or + ((minor == 4) and (teeny >= 4))))) + + if c['rubylibdir'] + # V > 1.6.3 + libruby = "#{c['prefix']}/lib/ruby" + librubyver = c['rubylibdir'] + librubyverarch = c['archdir'] + siteruby = c['sitedir'] + siterubyver = c['sitelibdir'] + siterubyverarch = c['sitearchdir'] + elsif newpath_p + # 1.4.4 <= V <= 1.6.3 + libruby = "#{c['prefix']}/lib/ruby" + librubyver = "#{c['prefix']}/lib/ruby/#{version}" + librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" + siteruby = c['sitedir'] + siterubyver = "$siteruby/#{version}" + siterubyverarch = "$siterubyver/#{c['arch']}" + else + # V < 1.4.4 + libruby = "#{c['prefix']}/lib/ruby" + librubyver = "#{c['prefix']}/lib/ruby/#{version}" + librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" + siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" + siterubyver = siteruby + siterubyverarch = "$siterubyver/#{c['arch']}" + end + parameterize = lambda {|path| + path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') + } + + if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } + makeprog = arg.sub(/'/, '').split(/=/, 2)[1] + else + makeprog = 'make' + end + + [ + ExecItem.new('installdirs', 'std/site/home', + 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ + {|val, table| + case val + when 'std' + table['rbdir'] = '$librubyver' + table['sodir'] = '$librubyverarch' + when 'site' + table['rbdir'] = '$siterubyver' + table['sodir'] = '$siterubyverarch' + when 'home' + setup_rb_error '$HOME was not set' unless ENV['HOME'] + table['prefix'] = ENV['HOME'] + table['rbdir'] = '$libdir/ruby' + table['sodir'] = '$libdir/ruby' + end + }, + PathItem.new('prefix', 'path', c['prefix'], + 'path prefix of target environment'), + PathItem.new('bindir', 'path', parameterize.call(c['bindir']), + 'the directory for commands'), + PathItem.new('libdir', 'path', parameterize.call(c['libdir']), + 'the directory for libraries'), + PathItem.new('datadir', 'path', parameterize.call(c['datadir']), + 'the directory for shared data'), + PathItem.new('mandir', 'path', parameterize.call(c['mandir']), + 'the directory for man pages'), + PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), + 'the directory for system configuration files'), + PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), + 'the directory for local state data'), + PathItem.new('libruby', 'path', libruby, + 'the directory for ruby libraries'), + PathItem.new('librubyver', 'path', librubyver, + 'the directory for standard ruby libraries'), + PathItem.new('librubyverarch', 'path', librubyverarch, + 'the directory for standard ruby extensions'), + PathItem.new('siteruby', 'path', siteruby, + 'the directory for version-independent aux ruby libraries'), + PathItem.new('siterubyver', 'path', siterubyver, + 'the directory for aux ruby libraries'), + PathItem.new('siterubyverarch', 'path', siterubyverarch, + 'the directory for aux ruby binaries'), + PathItem.new('rbdir', 'path', '$siterubyver', + 'the directory for ruby scripts'), + PathItem.new('sodir', 'path', '$siterubyverarch', + 'the directory for ruby extentions'), + PathItem.new('rubypath', 'path', rubypath, + 'the path to set to #! line'), + ProgramItem.new('rubyprog', 'name', rubypath, + 'the ruby program using for installation'), + ProgramItem.new('makeprog', 'name', makeprog, + 'the make program to compile ruby extentions'), + SelectItem.new('shebang', 'all/ruby/never', 'ruby', + 'shebang line (#!) editing mode'), + BoolItem.new('without-ext', 'yes/no', 'no', + 'does not compile/install ruby extentions') + ] + end + private :standard_entries + + def load_multipackage_entries + multipackage_entries().each do |ent| + add ent + end + end + + def multipackage_entries + [ + PackageSelectionItem.new('with', 'name,name...', '', 'ALL', + 'package names that you want to install'), + PackageSelectionItem.new('without', 'name,name...', '', 'NONE', + 'package names that you do not want to install') + ] + end + private :multipackage_entries + + ALIASES = { + 'std-ruby' => 'librubyver', + 'stdruby' => 'librubyver', + 'rubylibdir' => 'librubyver', + 'archdir' => 'librubyverarch', + 'site-ruby-common' => 'siteruby', # For backward compatibility + 'site-ruby' => 'siterubyver', # For backward compatibility + 'bin-dir' => 'bindir', + 'bin-dir' => 'bindir', + 'rb-dir' => 'rbdir', + 'so-dir' => 'sodir', + 'data-dir' => 'datadir', + 'ruby-path' => 'rubypath', + 'ruby-prog' => 'rubyprog', + 'ruby' => 'rubyprog', + 'make-prog' => 'makeprog', + 'make' => 'makeprog' + } + + def fixup + ALIASES.each do |ali, name| + @table[ali] = @table[name] + end + @items.freeze + @table.freeze + @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ + end + + def parse_opt(opt) + m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" + m.to_a[1,2] + end + + def dllext + @rbconfig['DLEXT'] + end + + def value_config?(name) + lookup(name).value? + end + + class Item + def initialize(name, template, default, desc) + @name = name.freeze + @template = template + @value = default + @default = default + @description = desc + end + + attr_reader :name + attr_reader :description + + attr_accessor :default + alias help_default default + + def help_opt + "--#{@name}=#{@template}" + end + + def value? + true + end + + def value + @value + end + + def resolve(table) + @value.gsub(%r<\$([^/]+)>) { table[$1] } + end + + def set(val) + @value = check(val) + end + + private + + def check(val) + setup_rb_error "config: --#{name} requires argument" unless val + val + end + end + + class BoolItem < Item + def config_type + 'bool' + end + + def help_opt + "--#{@name}" + end + + private + + def check(val) + return 'yes' unless val + case val + when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' + when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' + else + setup_rb_error "config: --#{@name} accepts only yes/no for argument" + end + end + end + + class PathItem < Item + def config_type + 'path' + end + + private + + def check(path) + setup_rb_error "config: --#{@name} requires argument" unless path + path[0,1] == '$' ? path : File.expand_path(path) + end + end + + class ProgramItem < Item + def config_type + 'program' + end + end + + class SelectItem < Item + def initialize(name, selection, default, desc) + super + @ok = selection.split('/') + end + + def config_type + 'select' + end + + private + + def check(val) + unless @ok.include?(val.strip) + setup_rb_error "config: use --#{@name}=#{@template} (#{val})" + end + val.strip + end + end + + class ExecItem < Item + def initialize(name, selection, desc, &block) + super name, selection, nil, desc + @ok = selection.split('/') + @action = block + end + + def config_type + 'exec' + end + + def value? + false + end + + def resolve(table) + setup_rb_error "$#{name()} wrongly used as option value" + end + + undef set + + def evaluate(val, table) + v = val.strip.downcase + unless @ok.include?(v) + setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" + end + @action.call v, table + end + end + + class PackageSelectionItem < Item + def initialize(name, template, default, help_default, desc) + super name, template, default, desc + @help_default = help_default + end + + attr_reader :help_default + + def config_type + 'package' + end + + private + + def check(val) + unless File.dir?("packages/#{val}") + setup_rb_error "config: no such package: #{val}" + end + val + end + end + + class MetaConfigEnvironment + def initialize(config, installer) + @config = config + @installer = installer + end + + def config_names + @config.names + end + + def config?(name) + @config.key?(name) + end + + def bool_config?(name) + @config.lookup(name).config_type == 'bool' + end + + def path_config?(name) + @config.lookup(name).config_type == 'path' + end + + def value_config?(name) + @config.lookup(name).config_type != 'exec' + end + + def add_config(item) + @config.add item + end + + def add_bool_config(name, default, desc) + @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) + end + + def add_path_config(name, default, desc) + @config.add PathItem.new(name, 'path', default, desc) + end + + def set_config_default(name, default) + @config.lookup(name).default = default + end + + def remove_config(name) + @config.remove(name) + end + + # For only multipackage + def packages + raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer + @installer.packages + end + + # For only multipackage + def declare_packages(list) + raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer + @installer.packages = list + end + end + +end # class ConfigTable + + +# This module requires: #verbose?, #no_harm? +module FileOperations + + def mkdir_p(dirname, prefix = nil) + dirname = prefix + File.expand_path(dirname) if prefix + $stderr.puts "mkdir -p #{dirname}" if verbose? + return if no_harm? + + # Does not check '/', it's too abnormal. + dirs = File.expand_path(dirname).split(%r<(?=/)>) + if /\A[a-z]:\z/i =~ dirs[0] + disk = dirs.shift + dirs[0] = disk + dirs[0] + end + dirs.each_index do |idx| + path = dirs[0..idx].join('') + Dir.mkdir path unless File.dir?(path) + end + end + + def rm_f(path) + $stderr.puts "rm -f #{path}" if verbose? + return if no_harm? + force_remove_file path + end + + def rm_rf(path) + $stderr.puts "rm -rf #{path}" if verbose? + return if no_harm? + remove_tree path + end + + def remove_tree(path) + if File.symlink?(path) + remove_file path + elsif File.dir?(path) + remove_tree0 path + else + force_remove_file path + end + end + + def remove_tree0(path) + Dir.foreach(path) do |ent| + next if ent == '.' + next if ent == '..' + entpath = "#{path}/#{ent}" + if File.symlink?(entpath) + remove_file entpath + elsif File.dir?(entpath) + remove_tree0 entpath + else + force_remove_file entpath + end + end + begin + Dir.rmdir path + rescue Errno::ENOTEMPTY + # directory may not be empty + end + end + + def move_file(src, dest) + force_remove_file dest + begin + File.rename src, dest + rescue + File.open(dest, 'wb') {|f| + f.write File.binread(src) + } + File.chmod File.stat(src).mode, dest + File.unlink src + end + end + + def force_remove_file(path) + begin + remove_file path + rescue + end + end + + def remove_file(path) + File.chmod 0777, path + File.unlink path + end + + def install(from, dest, mode, prefix = nil) + $stderr.puts "install #{from} #{dest}" if verbose? + return if no_harm? + + realdest = prefix ? prefix + File.expand_path(dest) : dest + realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) + str = File.binread(from) + if diff?(str, realdest) + verbose_off { + rm_f realdest if File.exist?(realdest) + } + File.open(realdest, 'wb') {|f| + f.write str + } + File.chmod mode, realdest + + File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| + if prefix + f.puts realdest.sub(prefix, '') + else + f.puts realdest + end + } + end + end + + def diff?(new_content, path) + return true unless File.exist?(path) + new_content != File.binread(path) + end + + def command(*args) + $stderr.puts args.join(' ') if verbose? + system(*args) or raise RuntimeError, + "system(#{args.map{|a| a.inspect }.join(' ')}) failed" + end + + def ruby(*args) + command config('rubyprog'), *args + end + + def make(task = nil) + command(*[config('makeprog'), task].compact) + end + + def extdir?(dir) + File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") + end + + def files_of(dir) + Dir.open(dir) {|d| + return d.select {|ent| File.file?("#{dir}/#{ent}") } + } + end + + DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) + + def directories_of(dir) + Dir.open(dir) {|d| + return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT + } + end + +end + + +# This module requires: #srcdir_root, #objdir_root, #relpath +module HookScriptAPI + + def get_config(key) + @config[key] + end + + alias config get_config + + # obsolete: use metaconfig to change configuration + def set_config(key, val) + @config[key] = val + end + + # + # srcdir/objdir (works only in the package directory) + # + + def curr_srcdir + "#{srcdir_root()}/#{relpath()}" + end + + def curr_objdir + "#{objdir_root()}/#{relpath()}" + end + + def srcfile(path) + "#{curr_srcdir()}/#{path}" + end + + def srcexist?(path) + File.exist?(srcfile(path)) + end + + def srcdirectory?(path) + File.dir?(srcfile(path)) + end + + def srcfile?(path) + File.file?(srcfile(path)) + end + + def srcentries(path = '.') + Dir.open("#{curr_srcdir()}/#{path}") {|d| + return d.to_a - %w(. ..) + } + end + + def srcfiles(path = '.') + srcentries(path).select {|fname| + File.file?(File.join(curr_srcdir(), path, fname)) + } + end + + def srcdirectories(path = '.') + srcentries(path).select {|fname| + File.dir?(File.join(curr_srcdir(), path, fname)) + } + end + +end + + +class ToplevelInstaller + + Version = '3.4.1' + Copyright = 'Copyright (c) 2000-2005 Minero Aoki' + + TASKS = [ + [ 'all', 'do config, setup, then install' ], + [ 'config', 'saves your configurations' ], + [ 'show', 'shows current configuration' ], + [ 'setup', 'compiles ruby extentions and others' ], + [ 'install', 'installs files' ], + [ 'test', 'run all tests in test/' ], + [ 'clean', "does `make clean' for each extention" ], + [ 'distclean',"does `make distclean' for each extention" ] + ] + + def ToplevelInstaller.invoke + config = ConfigTable.new(load_rbconfig()) + config.load_standard_entries + config.load_multipackage_entries if multipackage? + config.fixup + klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) + klass.new(File.dirname($0), config).invoke + end + + def ToplevelInstaller.multipackage? + File.dir?(File.dirname($0) + '/packages') + end + + def ToplevelInstaller.load_rbconfig + if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } + ARGV.delete(arg) + load File.expand_path(arg.split(/=/, 2)[1]) + $".push 'rbconfig.rb' + else + require 'rbconfig' + end + ::Config::CONFIG + end + + def initialize(ardir_root, config) + @ardir = File.expand_path(ardir_root) + @config = config + # cache + @valid_task_re = nil + end + + def config(key) + @config[key] + end + + def inspect + "#<#{self.class} #{__id__()}>" + end + + def invoke + run_metaconfigs + case task = parsearg_global() + when nil, 'all' + parsearg_config + init_installers + exec_config + exec_setup + exec_install + else + case task + when 'config', 'test' + ; + when 'clean', 'distclean' + @config.load_savefile if File.exist?(@config.savefile) + else + @config.load_savefile + end + __send__ "parsearg_#{task}" + init_installers + __send__ "exec_#{task}" + end + end + + def run_metaconfigs + @config.load_script "#{@ardir}/metaconfig" + end + + def init_installers + @installer = Installer.new(@config, @ardir, File.expand_path('.')) + end + + # + # Hook Script API bases + # + + def srcdir_root + @ardir + end + + def objdir_root + '.' + end + + def relpath + '.' + end + + # + # Option Parsing + # + + def parsearg_global + while arg = ARGV.shift + case arg + when /\A\w+\z/ + setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) + return arg + when '-q', '--quiet' + @config.verbose = false + when '--verbose' + @config.verbose = true + when '--help' + print_usage $stdout + exit 0 + when '--version' + puts "#{File.basename($0)} version #{Version}" + exit 0 + when '--copyright' + puts Copyright + exit 0 + else + setup_rb_error "unknown global option '#{arg}'" + end + end + nil + end + + def valid_task?(t) + valid_task_re() =~ t + end + + def valid_task_re + @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ + end + + def parsearg_no_options + unless ARGV.empty? + task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) + setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" + end + end + + alias parsearg_show parsearg_no_options + alias parsearg_setup parsearg_no_options + alias parsearg_test parsearg_no_options + alias parsearg_clean parsearg_no_options + alias parsearg_distclean parsearg_no_options + + def parsearg_config + evalopt = [] + set = [] + @config.config_opt = [] + while i = ARGV.shift + if /\A--?\z/ =~ i + @config.config_opt = ARGV.dup + break + end + name, value = *@config.parse_opt(i) + if @config.value_config?(name) + @config[name] = value + else + evalopt.push [name, value] + end + set.push name + end + evalopt.each do |name, value| + @config.lookup(name).evaluate value, @config + end + # Check if configuration is valid + set.each do |n| + @config[n] if @config.value_config?(n) + end + end + + def parsearg_install + @config.no_harm = false + @config.install_prefix = '' + while a = ARGV.shift + case a + when '--no-harm' + @config.no_harm = true + when /\A--prefix=/ + path = a.split(/=/, 2)[1] + path = File.expand_path(path) unless path[0,1] == '/' + @config.install_prefix = path + else + setup_rb_error "install: unknown option #{a}" + end + end + end + + def print_usage(out) + out.puts 'Typical Installation Procedure:' + out.puts " $ ruby #{File.basename $0} config" + out.puts " $ ruby #{File.basename $0} setup" + out.puts " # ruby #{File.basename $0} install (may require root privilege)" + out.puts + out.puts 'Detailed Usage:' + out.puts " ruby #{File.basename $0} " + out.puts " ruby #{File.basename $0} [] []" + + fmt = " %-24s %s\n" + out.puts + out.puts 'Global options:' + out.printf fmt, '-q,--quiet', 'suppress message outputs' + out.printf fmt, ' --verbose', 'output messages verbosely' + out.printf fmt, ' --help', 'print this message' + out.printf fmt, ' --version', 'print version and quit' + out.printf fmt, ' --copyright', 'print copyright and quit' + out.puts + out.puts 'Tasks:' + TASKS.each do |name, desc| + out.printf fmt, name, desc + end + + fmt = " %-24s %s [%s]\n" + out.puts + out.puts 'Options for CONFIG or ALL:' + @config.each do |item| + out.printf fmt, item.help_opt, item.description, item.help_default + end + out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" + out.puts + out.puts 'Options for INSTALL:' + out.printf fmt, '--no-harm', 'only display what to do if given', 'off' + out.printf fmt, '--prefix=path', 'install path prefix', '' + out.puts + end + + # + # Task Handlers + # + + def exec_config + @installer.exec_config + @config.save # must be final + end + + def exec_setup + @installer.exec_setup + end + + def exec_install + @installer.exec_install + end + + def exec_test + @installer.exec_test + end + + def exec_show + @config.each do |i| + printf "%-20s %s\n", i.name, i.value if i.value? + end + end + + def exec_clean + @installer.exec_clean + end + + def exec_distclean + @installer.exec_distclean + end + +end # class ToplevelInstaller + + +class ToplevelInstallerMulti < ToplevelInstaller + + include FileOperations + + def initialize(ardir_root, config) + super + @packages = directories_of("#{@ardir}/packages") + raise 'no package exists' if @packages.empty? + @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) + end + + def run_metaconfigs + @config.load_script "#{@ardir}/metaconfig", self + @packages.each do |name| + @config.load_script "#{@ardir}/packages/#{name}/metaconfig" + end + end + + attr_reader :packages + + def packages=(list) + raise 'package list is empty' if list.empty? + list.each do |name| + raise "directory packages/#{name} does not exist"\ + unless File.dir?("#{@ardir}/packages/#{name}") + end + @packages = list + end + + def init_installers + @installers = {} + @packages.each do |pack| + @installers[pack] = Installer.new(@config, + "#{@ardir}/packages/#{pack}", + "packages/#{pack}") + end + with = extract_selection(config('with')) + without = extract_selection(config('without')) + @selected = @installers.keys.select {|name| + (with.empty? or with.include?(name)) \ + and not without.include?(name) + } + end + + def extract_selection(list) + a = list.split(/,/) + a.each do |name| + setup_rb_error "no such package: #{name}" unless @installers.key?(name) + end + a + end + + def print_usage(f) + super + f.puts 'Inluded packages:' + f.puts ' ' + @packages.sort.join(' ') + f.puts + end + + # + # Task Handlers + # + + def exec_config + run_hook 'pre-config' + each_selected_installers {|inst| inst.exec_config } + run_hook 'post-config' + @config.save # must be final + end + + def exec_setup + run_hook 'pre-setup' + each_selected_installers {|inst| inst.exec_setup } + run_hook 'post-setup' + end + + def exec_install + run_hook 'pre-install' + each_selected_installers {|inst| inst.exec_install } + run_hook 'post-install' + end + + def exec_test + run_hook 'pre-test' + each_selected_installers {|inst| inst.exec_test } + run_hook 'post-test' + end + + def exec_clean + rm_f @config.savefile + run_hook 'pre-clean' + each_selected_installers {|inst| inst.exec_clean } + run_hook 'post-clean' + end + + def exec_distclean + rm_f @config.savefile + run_hook 'pre-distclean' + each_selected_installers {|inst| inst.exec_distclean } + run_hook 'post-distclean' + end + + # + # lib + # + + def each_selected_installers + Dir.mkdir 'packages' unless File.dir?('packages') + @selected.each do |pack| + $stderr.puts "Processing the package `#{pack}' ..." if verbose? + Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") + Dir.chdir "packages/#{pack}" + yield @installers[pack] + Dir.chdir '../..' + end + end + + def run_hook(id) + @root_installer.run_hook id + end + + # module FileOperations requires this + def verbose? + @config.verbose? + end + + # module FileOperations requires this + def no_harm? + @config.no_harm? + end + +end # class ToplevelInstallerMulti + + +class Installer + + FILETYPES = %w( bin lib ext data conf man ) + + include FileOperations + include HookScriptAPI + + def initialize(config, srcroot, objroot) + @config = config + @srcdir = File.expand_path(srcroot) + @objdir = File.expand_path(objroot) + @currdir = '.' + end + + def inspect + "#<#{self.class} #{File.basename(@srcdir)}>" + end + + def noop(rel) + end + + # + # Hook Script API base methods + # + + def srcdir_root + @srcdir + end + + def objdir_root + @objdir + end + + def relpath + @currdir + end + + # + # Config Access + # + + # module FileOperations requires this + def verbose? + @config.verbose? + end + + # module FileOperations requires this + def no_harm? + @config.no_harm? + end + + def verbose_off + begin + save, @config.verbose = @config.verbose?, false + yield + ensure + @config.verbose = save + end + end + + # + # TASK config + # + + def exec_config + exec_task_traverse 'config' + end + + alias config_dir_bin noop + alias config_dir_lib noop + + def config_dir_ext(rel) + extconf if extdir?(curr_srcdir()) + end + + alias config_dir_data noop + alias config_dir_conf noop + alias config_dir_man noop + + def extconf + ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt + end + + # + # TASK setup + # + + def exec_setup + exec_task_traverse 'setup' + end + + def setup_dir_bin(rel) + files_of(curr_srcdir()).each do |fname| + update_shebang_line "#{curr_srcdir()}/#{fname}" + end + end + + alias setup_dir_lib noop + + def setup_dir_ext(rel) + make if extdir?(curr_srcdir()) + end + + alias setup_dir_data noop + alias setup_dir_conf noop + alias setup_dir_man noop + + def update_shebang_line(path) + return if no_harm? + return if config('shebang') == 'never' + old = Shebang.load(path) + if old + $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1 + new = new_shebang(old) + return if new.to_s == old.to_s + else + return unless config('shebang') == 'all' + new = Shebang.new(config('rubypath')) + end + $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? + open_atomic_writer(path) {|output| + File.open(path, 'rb') {|f| + f.gets if old # discard + output.puts new.to_s + output.print f.read + } + } + end + + def new_shebang(old) + if /\Aruby/ =~ File.basename(old.cmd) + Shebang.new(config('rubypath'), old.args) + elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' + Shebang.new(config('rubypath'), old.args[1..-1]) + else + return old unless config('shebang') == 'all' + Shebang.new(config('rubypath')) + end + end + + def open_atomic_writer(path, &block) + tmpfile = File.basename(path) + '.tmp' + begin + File.open(tmpfile, 'wb', &block) + File.rename tmpfile, File.basename(path) + ensure + File.unlink tmpfile if File.exist?(tmpfile) + end + end + + class Shebang + def Shebang.load(path) + line = nil + File.open(path) {|f| + line = f.gets + } + return nil unless /\A#!/ =~ line + parse(line) + end + + def Shebang.parse(line) + cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') + new(cmd, args) + end + + def initialize(cmd, args = []) + @cmd = cmd + @args = args + end + + attr_reader :cmd + attr_reader :args + + def to_s + "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") + end + end + + # + # TASK install + # + + def exec_install + rm_f 'InstalledFiles' + exec_task_traverse 'install' + end + + def install_dir_bin(rel) + install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 + end + + def install_dir_lib(rel) + install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644 + end + + def install_dir_ext(rel) + return unless extdir?(curr_srcdir()) + install_files rubyextentions('.'), + "#{config('sodir')}/#{File.dirname(rel)}", + 0555 + end + + def install_dir_data(rel) + install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 + end + + def install_dir_conf(rel) + # FIXME: should not remove current config files + # (rename previous file to .old/.org) + install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 + end + + def install_dir_man(rel) + install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 + end + + def install_files(list, dest, mode) + mkdir_p dest, @config.install_prefix + list.each do |fname| + install fname, dest, mode, @config.install_prefix + end + end + + def libfiles + glob_reject(%w(*.y *.output), targetfiles()) + end + + def rubyextentions(dir) + ents = glob_select("*.#{@config.dllext}", targetfiles()) + if ents.empty? + setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" + end + ents + end + + def targetfiles + mapdir(existfiles() - hookfiles()) + end + + def mapdir(ents) + ents.map {|ent| + if File.exist?(ent) + then ent # objdir + else "#{curr_srcdir()}/#{ent}" # srcdir + end + } + end + + # picked up many entries from cvs-1.11.1/src/ignore.c + JUNK_FILES = %w( + core RCSLOG tags TAGS .make.state + .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb + *~ *.old *.bak *.BAK *.orig *.rej _$* *$ + + *.org *.in .* + ) + + def existfiles + glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) + end + + def hookfiles + %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| + %w( config setup install clean ).map {|t| sprintf(fmt, t) } + }.flatten + end + + def glob_select(pat, ents) + re = globs2re([pat]) + ents.select {|ent| re =~ ent } + end + + def glob_reject(pats, ents) + re = globs2re(pats) + ents.reject {|ent| re =~ ent } + end + + GLOB2REGEX = { + '.' => '\.', + '$' => '\$', + '#' => '\#', + '*' => '.*' + } + + def globs2re(pats) + /\A(?:#{ + pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') + })\z/ + end + + # + # TASK test + # + + TESTDIR = 'test' + + def exec_test + unless File.directory?('test') + $stderr.puts 'no test in this package' if verbose? + return + end + $stderr.puts 'Running tests...' if verbose? + begin + require 'test/unit' + rescue LoadError + setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' + end + runner = Test::Unit::AutoRunner.new(true) + runner.to_run << TESTDIR + runner.run + end + + # + # TASK clean + # + + def exec_clean + exec_task_traverse 'clean' + rm_f @config.savefile + rm_f 'InstalledFiles' + end + + alias clean_dir_bin noop + alias clean_dir_lib noop + alias clean_dir_data noop + alias clean_dir_conf noop + alias clean_dir_man noop + + def clean_dir_ext(rel) + return unless extdir?(curr_srcdir()) + make 'clean' if File.file?('Makefile') + end + + # + # TASK distclean + # + + def exec_distclean + exec_task_traverse 'distclean' + rm_f @config.savefile + rm_f 'InstalledFiles' + end + + alias distclean_dir_bin noop + alias distclean_dir_lib noop + + def distclean_dir_ext(rel) + return unless extdir?(curr_srcdir()) + make 'distclean' if File.file?('Makefile') + end + + alias distclean_dir_data noop + alias distclean_dir_conf noop + alias distclean_dir_man noop + + # + # Traversing + # + + def exec_task_traverse(task) + run_hook "pre-#{task}" + FILETYPES.each do |type| + if type == 'ext' and config('without-ext') == 'yes' + $stderr.puts 'skipping ext/* by user option' if verbose? + next + end + traverse task, type, "#{task}_dir_#{type}" + end + run_hook "post-#{task}" + end + + def traverse(task, rel, mid) + dive_into(rel) { + run_hook "pre-#{task}" + __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') + directories_of(curr_srcdir()).each do |d| + traverse task, "#{rel}/#{d}", mid + end + run_hook "post-#{task}" + } + end + + def dive_into(rel) + return unless File.dir?("#{@srcdir}/#{rel}") + + dir = File.basename(rel) + Dir.mkdir dir unless File.dir?(dir) + prevdir = Dir.pwd + Dir.chdir dir + $stderr.puts '---> ' + rel if verbose? + @currdir = rel + yield + Dir.chdir prevdir + $stderr.puts '<--- ' + rel if verbose? + @currdir = File.dirname(rel) + end + + def run_hook(id) + path = [ "#{curr_srcdir()}/#{id}", + "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } + return unless path + begin + instance_eval File.read(path), path, 1 + rescue + raise if $DEBUG + setup_rb_error "hook #{path} failed:\n" + $!.message + end + end + +end # class Installer + + +class SetupError < StandardError; end + +def setup_rb_error(msg) + raise SetupError, msg +end + +if $0 == __FILE__ + begin + ToplevelInstaller.invoke + rescue SetupError + raise if $DEBUG + $stderr.puts $!.message + $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." + exit 1 + end +end diff --git a/vendor/gems/polyglot-0.2.5/tasks/deployment.rake b/vendor/gems/polyglot-0.2.5/tasks/deployment.rake new file mode 100755 index 0000000..2f43742 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/tasks/deployment.rake @@ -0,0 +1,34 @@ +desc 'Release the website and new gem version' +task :deploy => [:check_version, :website, :release] do + puts "Remember to create SVN tag:" + puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " + + "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} " + puts "Suggested comment:" + puts "Tagging release #{CHANGES}" +end + +desc 'Runs tasks website_generate and install_gem as a local deployment of the gem' +task :local_deploy => [:website_generate, :install_gem] + +task :check_version do + unless ENV['VERSION'] + puts 'Must pass a VERSION=x.y.z release version' + exit + end + unless ENV['VERSION'] == VERS + puts "Please update your version.rb to match the release version, currently #{VERS}" + exit + end +end + +desc 'Install the package as a gem, without generating documentation(ri/rdoc)' +task :install_gem_no_doc => [:clean, :package] do + sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri" +end + +namespace :manifest do + desc 'Recreate Manifest.txt to include ALL files' + task :refresh do + `rake check_manifest | patch -p0 > Manifest.txt` + end +end \ No newline at end of file diff --git a/vendor/gems/polyglot-0.2.5/tasks/environment.rake b/vendor/gems/polyglot-0.2.5/tasks/environment.rake new file mode 100755 index 0000000..691ed3b --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/tasks/environment.rake @@ -0,0 +1,7 @@ +task :ruby_env do + RUBY_APP = if RUBY_PLATFORM =~ /java/ + "jruby" + else + "ruby" + end unless defined? RUBY_APP +end diff --git a/vendor/gems/polyglot-0.2.5/tasks/website.rake b/vendor/gems/polyglot-0.2.5/tasks/website.rake new file mode 100755 index 0000000..93e03fa --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/tasks/website.rake @@ -0,0 +1,17 @@ +desc 'Generate website files' +task :website_generate => :ruby_env do + (Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt| + sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} } + end +end + +desc 'Upload website files to rubyforge' +task :website_upload do + host = "#{rubyforge_username}@rubyforge.org" + remote_dir = "/var/www/gforge-projects/#{PATH}/" + local_dir = 'website' + sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}} +end + +desc 'Generate and upload website files' +task :website => [:website_generate, :website_upload, :publish_docs] diff --git a/vendor/gems/polyglot-0.2.5/test/test_helper.rb b/vendor/gems/polyglot-0.2.5/test/test_helper.rb new file mode 100755 index 0000000..1f9d389 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/test/test_helper.rb @@ -0,0 +1,2 @@ +require 'test/unit' +require File.dirname(__FILE__) + '/../lib/polyglot' diff --git a/vendor/gems/polyglot-0.2.5/test/test_polyglot.rb b/vendor/gems/polyglot-0.2.5/test/test_polyglot.rb new file mode 100755 index 0000000..255fa7a --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/test/test_polyglot.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/test_helper.rb' + +class TestPolyglot < Test::Unit::TestCase + + def setup + end + + def test_truth + assert true + end +end diff --git a/vendor/gems/polyglot-0.2.5/website/index.html b/vendor/gems/polyglot-0.2.5/website/index.html new file mode 100755 index 0000000..c50e291 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/website/index.html @@ -0,0 +1,100 @@ + + + + + + + polyglot + + + + + + +
+ +

polyglot

+
+

Get Version

+ 0.2.5 +
+

Poly => many, glot => languages

+

What

+

Polyglot provides a registry of file types that can be loaded by
+calling its improved version of ‘require’. Each file extension
+that can be handled by a custom loader is registered by calling
+Polyglot.register(“ext”, <class>), and then you can simply
+require “somefile”, which will find and load “somefile.ext”
+using your custom loader.

+

This supports the creation of DSLs having a syntax that is most
+appropriate to their purpose, instead of abusing the Ruby syntax.

+

Required files are attempted first using the normal Ruby loader,
+and if that fails, Polyglot conducts a search for a file having
+a supported extension.

+

Installing

+

sudo gem install polyglot

+

Example

+

Define and register your file type loader in file rubyglot.rb:

+require ‘polyglot’ +class RubyglotLoader +def self.load(filename, options = nil, &block) +File.open(filename) {|file| +# Load the contents of file as Ruby code: +# Implement your parser here instead! +Kernel.eval(file.read) +} +end +end +Polyglot.register(“rgl”, RubyglotLoader) +

This file, hello.rgl, will be loaded (this simple example uses Ruby code):

+puts “Initializing” +class Hello +def initialize() +puts “Hello, world\n” +end +end +

Call it from file test.rb:

+require ‘rubyglot’ # Create my file type handler +require ‘hello’ # Can add extra options or even a block here +puts “Ready to go” +Hello.new +

Run:

+$ ruby test.rb +Initializing +Ready to go +Hello, world +$ +

How to submit patches

+

Read the 8 steps for fixing other people’s code and for section 8z: Submit patch, email me on the link below.

+

The trunk repository is svn://rubyforge.org/var/svn/polyglot/trunk for anonymous access.

+

License

+

This code is free to use under the terms of the MIT license.

+

Contact

+

Comments are welcome. Send an email to Clifford Heath

+

+ Clifford Heath, 29th January 2009
+ Theme extended from Paul Battley +

+
+ + + + + diff --git a/vendor/gems/polyglot-0.2.5/website/index.txt b/vendor/gems/polyglot-0.2.5/website/index.txt new file mode 100755 index 0000000..c389056 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/website/index.txt @@ -0,0 +1,79 @@ +h1. polyglot + +h2. Poly => many, glot => languages + + +h2. What + +Polyglot provides a registry of file types that can be loaded by +calling its improved version of 'require'. Each file extension +that can be handled by a custom loader is registered by calling +Polyglot.register("ext", <class>), and then you can simply +require "somefile", which will find and load "somefile.ext" +using your custom loader. + +This supports the creation of DSLs having a syntax that is most +appropriate to their purpose, instead of abusing the Ruby syntax. + +Required files are attempted first using the normal Ruby loader, +and if that fails, Polyglot conducts a search for a file having +a supported extension. + +h2. Installing + +
sudo gem install polyglot
+ +h2. Example + +Define and register your file type loader in file rubyglot.rb: + + require 'polyglot' + class RubyglotLoader + def self.load(filename, options = nil, &block) + File.open(filename) {|file| + # Load the contents of file as Ruby code: + # Implement your parser here instead! + Kernel.eval(file.read) + } + end + end + Polyglot.register("rgl", RubyglotLoader) + +This file, hello.rgl, will be loaded (this simple example uses Ruby code): + + puts "Initializing" + class Hello + def initialize() + puts "Hello, world\n" + end + end + +Call it from file test.rb: + + require 'rubyglot' # Create my file type handler + require 'hello' # Can add extra options or even a block here + puts "Ready to go" + Hello.new + +Run: + + $ ruby test.rb + Initializing + Ready to go + Hello, world + $ + + +h2. How to submit patches + +Read the "8 steps for fixing other people's code":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/ and for section "8z: Submit patch":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/#8z-email, email me on the link below. + +The trunk repository is svn://rubyforge.org/var/svn/polyglot/trunk for anonymous access. + +h2. License + +This code is free to use under the terms of the MIT license. + +h2. Contact + +Comments are welcome. Send an email to "Clifford Heath":mailto:cjheath@rubyforge.org diff --git a/vendor/gems/polyglot-0.2.5/website/javascripts/rounded_corners_lite.inc.js b/vendor/gems/polyglot-0.2.5/website/javascripts/rounded_corners_lite.inc.js new file mode 100755 index 0000000..afc3ea3 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/website/javascripts/rounded_corners_lite.inc.js @@ -0,0 +1,285 @@ + + /**************************************************************** + * * + * curvyCorners * + * ------------ * + * * + * This script generates rounded corners for your divs. * + * * + * Version 1.2.9 * + * Copyright (c) 2006 Cameron Cooke * + * By: Cameron Cooke and Tim Hutchison. * + * * + * * + * Website: http://www.curvycorners.net * + * Email: info@totalinfinity.com * + * Forum: http://www.curvycorners.net/forum/ * + * * + * * + * This library is free software; you can redistribute * + * it and/or modify it under the terms of the GNU * + * Lesser General Public License as published by the * + * Free Software Foundation; either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will * + * be useful, but WITHOUT ANY WARRANTY; without even the * + * implied warranty of MERCHANTABILITY or FITNESS FOR A * + * PARTICULAR PURPOSE. See the GNU Lesser General Public * + * License for more details. * + * * + * You should have received a copy of the GNU Lesser * + * General Public License along with this library; * + * Inc., 59 Temple Place, Suite 330, Boston, * + * MA 02111-1307 USA * + * * + ****************************************************************/ + +var isIE = navigator.userAgent.toLowerCase().indexOf("msie") > -1; var isMoz = document.implementation && document.implementation.createDocument; var isSafari = ((navigator.userAgent.toLowerCase().indexOf('safari')!=-1)&&(navigator.userAgent.toLowerCase().indexOf('mac')!=-1))?true:false; function curvyCorners() +{ if(typeof(arguments[0]) != "object") throw newCurvyError("First parameter of curvyCorners() must be an object."); if(typeof(arguments[1]) != "object" && typeof(arguments[1]) != "string") throw newCurvyError("Second parameter of curvyCorners() must be an object or a class name."); if(typeof(arguments[1]) == "string") +{ var startIndex = 0; var boxCol = getElementsByClass(arguments[1]);} +else +{ var startIndex = 1; var boxCol = arguments;} +var curvyCornersCol = new Array(); if(arguments[0].validTags) +var validElements = arguments[0].validTags; else +var validElements = ["div"]; for(var i = startIndex, j = boxCol.length; i < j; i++) +{ var currentTag = boxCol[i].tagName.toLowerCase(); if(inArray(validElements, currentTag) !== false) +{ curvyCornersCol[curvyCornersCol.length] = new curvyObject(arguments[0], boxCol[i]);} +} +this.objects = curvyCornersCol; this.applyCornersToAll = function() +{ for(var x = 0, k = this.objects.length; x < k; x++) +{ this.objects[x].applyCorners();} +} +} +function curvyObject() +{ this.box = arguments[1]; this.settings = arguments[0]; this.topContainer = null; this.bottomContainer = null; this.masterCorners = new Array(); this.contentDIV = null; var boxHeight = get_style(this.box, "height", "height"); var boxWidth = get_style(this.box, "width", "width"); var borderWidth = get_style(this.box, "borderTopWidth", "border-top-width"); var borderColour = get_style(this.box, "borderTopColor", "border-top-color"); var boxColour = get_style(this.box, "backgroundColor", "background-color"); var backgroundImage = get_style(this.box, "backgroundImage", "background-image"); var boxPosition = get_style(this.box, "position", "position"); var boxPadding = get_style(this.box, "paddingTop", "padding-top"); this.boxHeight = parseInt(((boxHeight != "" && boxHeight != "auto" && boxHeight.indexOf("%") == -1)? boxHeight.substring(0, boxHeight.indexOf("px")) : this.box.scrollHeight)); this.boxWidth = parseInt(((boxWidth != "" && boxWidth != "auto" && boxWidth.indexOf("%") == -1)? boxWidth.substring(0, boxWidth.indexOf("px")) : this.box.scrollWidth)); this.borderWidth = parseInt(((borderWidth != "" && borderWidth.indexOf("px") !== -1)? borderWidth.slice(0, borderWidth.indexOf("px")) : 0)); this.boxColour = format_colour(boxColour); this.boxPadding = parseInt(((boxPadding != "" && boxPadding.indexOf("px") !== -1)? boxPadding.slice(0, boxPadding.indexOf("px")) : 0)); this.borderColour = format_colour(borderColour); this.borderString = this.borderWidth + "px" + " solid " + this.borderColour; this.backgroundImage = ((backgroundImage != "none")? backgroundImage : ""); this.boxContent = this.box.innerHTML; if(boxPosition != "absolute") this.box.style.position = "relative"; this.box.style.padding = "0px"; if(isIE && boxWidth == "auto" && boxHeight == "auto") this.box.style.width = "100%"; if(this.settings.autoPad == true && this.boxPadding > 0) +this.box.innerHTML = ""; this.applyCorners = function() +{ for(var t = 0; t < 2; t++) +{ switch(t) +{ case 0: +if(this.settings.tl || this.settings.tr) +{ var newMainContainer = document.createElement("DIV"); newMainContainer.style.width = "100%"; newMainContainer.style.fontSize = "1px"; newMainContainer.style.overflow = "hidden"; newMainContainer.style.position = "absolute"; newMainContainer.style.paddingLeft = this.borderWidth + "px"; newMainContainer.style.paddingRight = this.borderWidth + "px"; var topMaxRadius = Math.max(this.settings.tl ? this.settings.tl.radius : 0, this.settings.tr ? this.settings.tr.radius : 0); newMainContainer.style.height = topMaxRadius + "px"; newMainContainer.style.top = 0 - topMaxRadius + "px"; newMainContainer.style.left = 0 - this.borderWidth + "px"; this.topContainer = this.box.appendChild(newMainContainer);} +break; case 1: +if(this.settings.bl || this.settings.br) +{ var newMainContainer = document.createElement("DIV"); newMainContainer.style.width = "100%"; newMainContainer.style.fontSize = "1px"; newMainContainer.style.overflow = "hidden"; newMainContainer.style.position = "absolute"; newMainContainer.style.paddingLeft = this.borderWidth + "px"; newMainContainer.style.paddingRight = this.borderWidth + "px"; var botMaxRadius = Math.max(this.settings.bl ? this.settings.bl.radius : 0, this.settings.br ? this.settings.br.radius : 0); newMainContainer.style.height = botMaxRadius + "px"; newMainContainer.style.bottom = 0 - botMaxRadius + "px"; newMainContainer.style.left = 0 - this.borderWidth + "px"; this.bottomContainer = this.box.appendChild(newMainContainer);} +break;} +} +if(this.topContainer) this.box.style.borderTopWidth = "0px"; if(this.bottomContainer) this.box.style.borderBottomWidth = "0px"; var corners = ["tr", "tl", "br", "bl"]; for(var i in corners) +{ if(i > -1 < 4) +{ var cc = corners[i]; if(!this.settings[cc]) +{ if(((cc == "tr" || cc == "tl") && this.topContainer != null) || ((cc == "br" || cc == "bl") && this.bottomContainer != null)) +{ var newCorner = document.createElement("DIV"); newCorner.style.position = "relative"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; if(this.backgroundImage == "") +newCorner.style.backgroundColor = this.boxColour; else +newCorner.style.backgroundImage = this.backgroundImage; switch(cc) +{ case "tl": +newCorner.style.height = topMaxRadius - this.borderWidth + "px"; newCorner.style.marginRight = this.settings.tr.radius - (this.borderWidth*2) + "px"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.left = -this.borderWidth + "px"; break; case "tr": +newCorner.style.height = topMaxRadius - this.borderWidth + "px"; newCorner.style.marginLeft = this.settings.tl.radius - (this.borderWidth*2) + "px"; newCorner.style.borderRight = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.backgroundPosition = "-" + (topMaxRadius + this.borderWidth) + "px 0px"; newCorner.style.left = this.borderWidth + "px"; break; case "bl": +newCorner.style.height = botMaxRadius - this.borderWidth + "px"; newCorner.style.marginRight = this.settings.br.radius - (this.borderWidth*2) + "px"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = -this.borderWidth + "px"; newCorner.style.backgroundPosition = "-" + (this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px"; break; case "br": +newCorner.style.height = botMaxRadius - this.borderWidth + "px"; newCorner.style.marginLeft = this.settings.bl.radius - (this.borderWidth*2) + "px"; newCorner.style.borderRight = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = this.borderWidth + "px" +newCorner.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px"; break;} +} +} +else +{ if(this.masterCorners[this.settings[cc].radius]) +{ var newCorner = this.masterCorners[this.settings[cc].radius].cloneNode(true);} +else +{ var newCorner = document.createElement("DIV"); newCorner.style.height = this.settings[cc].radius + "px"; newCorner.style.width = this.settings[cc].radius + "px"; newCorner.style.position = "absolute"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; var borderRadius = parseInt(this.settings[cc].radius - this.borderWidth); for(var intx = 0, j = this.settings[cc].radius; intx < j; intx++) +{ if((intx +1) >= borderRadius) +var y1 = -1; else +var y1 = (Math.floor(Math.sqrt(Math.pow(borderRadius, 2) - Math.pow((intx+1), 2))) - 1); if(borderRadius != j) +{ if((intx) >= borderRadius) +var y2 = -1; else +var y2 = Math.ceil(Math.sqrt(Math.pow(borderRadius,2) - Math.pow(intx, 2))); if((intx+1) >= j) +var y3 = -1; else +var y3 = (Math.floor(Math.sqrt(Math.pow(j ,2) - Math.pow((intx+1), 2))) - 1);} +if((intx) >= j) +var y4 = -1; else +var y4 = Math.ceil(Math.sqrt(Math.pow(j ,2) - Math.pow(intx, 2))); if(y1 > -1) this.drawPixel(intx, 0, this.boxColour, 100, (y1+1), newCorner, -1, this.settings[cc].radius); if(borderRadius != j) +{ for(var inty = (y1 + 1); inty < y2; inty++) +{ if(this.settings.antiAlias) +{ if(this.backgroundImage != "") +{ var borderFract = (pixelFraction(intx, inty, borderRadius) * 100); if(borderFract < 30) +{ this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, 0, this.settings[cc].radius);} +else +{ this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, -1, this.settings[cc].radius);} +} +else +{ var pixelcolour = BlendColour(this.boxColour, this.borderColour, pixelFraction(intx, inty, borderRadius)); this.drawPixel(intx, inty, pixelcolour, 100, 1, newCorner, 0, this.settings[cc].radius, cc);} +} +} +if(this.settings.antiAlias) +{ if(y3 >= y2) +{ if (y2 == -1) y2 = 0; this.drawPixel(intx, y2, this.borderColour, 100, (y3 - y2 + 1), newCorner, 0, 0);} +} +else +{ if(y3 >= y1) +{ this.drawPixel(intx, (y1 + 1), this.borderColour, 100, (y3 - y1), newCorner, 0, 0);} +} +var outsideColour = this.borderColour;} +else +{ var outsideColour = this.boxColour; var y3 = y1;} +if(this.settings.antiAlias) +{ for(var inty = (y3 + 1); inty < y4; inty++) +{ this.drawPixel(intx, inty, outsideColour, (pixelFraction(intx, inty , j) * 100), 1, newCorner, ((this.borderWidth > 0)? 0 : -1), this.settings[cc].radius);} +} +} +this.masterCorners[this.settings[cc].radius] = newCorner.cloneNode(true);} +if(cc != "br") +{ for(var t = 0, k = newCorner.childNodes.length; t < k; t++) +{ var pixelBar = newCorner.childNodes[t]; var pixelBarTop = parseInt(pixelBar.style.top.substring(0, pixelBar.style.top.indexOf("px"))); var pixelBarLeft = parseInt(pixelBar.style.left.substring(0, pixelBar.style.left.indexOf("px"))); var pixelBarHeight = parseInt(pixelBar.style.height.substring(0, pixelBar.style.height.indexOf("px"))); if(cc == "tl" || cc == "bl"){ pixelBar.style.left = this.settings[cc].radius -pixelBarLeft -1 + "px";} +if(cc == "tr" || cc == "tl"){ pixelBar.style.top = this.settings[cc].radius -pixelBarHeight -pixelBarTop + "px";} +switch(cc) +{ case "tr": +pixelBar.style.backgroundPosition = "-" + Math.abs((this.boxWidth - this.settings[cc].radius + this.borderWidth) + pixelBarLeft) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px"; break; case "tl": +pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px"; break; case "bl": +pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs((this.boxHeight + this.settings[cc].radius + pixelBarTop) -this.borderWidth) + "px"; break;} +} +} +} +if(newCorner) +{ switch(cc) +{ case "tl": +if(newCorner.style.position == "absolute") newCorner.style.top = "0px"; if(newCorner.style.position == "absolute") newCorner.style.left = "0px"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case "tr": +if(newCorner.style.position == "absolute") newCorner.style.top = "0px"; if(newCorner.style.position == "absolute") newCorner.style.right = "0px"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case "bl": +if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px"; if(newCorner.style.position == "absolute") newCorner.style.left = "0px"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break; case "br": +if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px"; if(newCorner.style.position == "absolute") newCorner.style.right = "0px"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break;} +} +} +} +var radiusDiff = new Array(); radiusDiff["t"] = Math.abs(this.settings.tl.radius - this.settings.tr.radius) +radiusDiff["b"] = Math.abs(this.settings.bl.radius - this.settings.br.radius); for(z in radiusDiff) +{ if(z == "t" || z == "b") +{ if(radiusDiff[z]) +{ var smallerCornerType = ((this.settings[z + "l"].radius < this.settings[z + "r"].radius)? z +"l" : z +"r"); var newFiller = document.createElement("DIV"); newFiller.style.height = radiusDiff[z] + "px"; newFiller.style.width = this.settings[smallerCornerType].radius+ "px" +newFiller.style.position = "absolute"; newFiller.style.fontSize = "1px"; newFiller.style.overflow = "hidden"; newFiller.style.backgroundColor = this.boxColour; switch(smallerCornerType) +{ case "tl": +newFiller.style.bottom = "0px"; newFiller.style.left = "0px"; newFiller.style.borderLeft = this.borderString; this.topContainer.appendChild(newFiller); break; case "tr": +newFiller.style.bottom = "0px"; newFiller.style.right = "0px"; newFiller.style.borderRight = this.borderString; this.topContainer.appendChild(newFiller); break; case "bl": +newFiller.style.top = "0px"; newFiller.style.left = "0px"; newFiller.style.borderLeft = this.borderString; this.bottomContainer.appendChild(newFiller); break; case "br": +newFiller.style.top = "0px"; newFiller.style.right = "0px"; newFiller.style.borderRight = this.borderString; this.bottomContainer.appendChild(newFiller); break;} +} +var newFillerBar = document.createElement("DIV"); newFillerBar.style.position = "relative"; newFillerBar.style.fontSize = "1px"; newFillerBar.style.overflow = "hidden"; newFillerBar.style.backgroundColor = this.boxColour; newFillerBar.style.backgroundImage = this.backgroundImage; switch(z) +{ case "t": +if(this.topContainer) +{ if(this.settings.tl.radius && this.settings.tr.radius) +{ newFillerBar.style.height = topMaxRadius - this.borderWidth + "px"; newFillerBar.style.marginLeft = this.settings.tl.radius - this.borderWidth + "px"; newFillerBar.style.marginRight = this.settings.tr.radius - this.borderWidth + "px"; newFillerBar.style.borderTop = this.borderString; if(this.backgroundImage != "") +newFillerBar.style.backgroundPosition = "-" + (topMaxRadius + this.borderWidth) + "px 0px"; this.topContainer.appendChild(newFillerBar);} +this.box.style.backgroundPosition = "0px -" + (topMaxRadius - this.borderWidth) + "px";} +break; case "b": +if(this.bottomContainer) +{ if(this.settings.bl.radius && this.settings.br.radius) +{ newFillerBar.style.height = botMaxRadius - this.borderWidth + "px"; newFillerBar.style.marginLeft = this.settings.bl.radius - this.borderWidth + "px"; newFillerBar.style.marginRight = this.settings.br.radius - this.borderWidth + "px"; newFillerBar.style.borderBottom = this.borderString; if(this.backgroundImage != "") +newFillerBar.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (topMaxRadius + this.borderWidth)) + "px"; this.bottomContainer.appendChild(newFillerBar);} +} +break;} +} +} +if(this.settings.autoPad == true && this.boxPadding > 0) +{ var contentContainer = document.createElement("DIV"); contentContainer.style.position = "relative"; contentContainer.innerHTML = this.boxContent; contentContainer.className = "autoPadDiv"; var topPadding = Math.abs(topMaxRadius - this.boxPadding); var botPadding = Math.abs(botMaxRadius - this.boxPadding); if(topMaxRadius < this.boxPadding) +contentContainer.style.paddingTop = topPadding + "px"; if(botMaxRadius < this.boxPadding) +contentContainer.style.paddingBottom = botMaxRadius + "px"; contentContainer.style.paddingLeft = this.boxPadding + "px"; contentContainer.style.paddingRight = this.boxPadding + "px"; this.contentDIV = this.box.appendChild(contentContainer);} +} +this.drawPixel = function(intx, inty, colour, transAmount, height, newCorner, image, cornerRadius) +{ var pixel = document.createElement("DIV"); pixel.style.height = height + "px"; pixel.style.width = "1px"; pixel.style.position = "absolute"; pixel.style.fontSize = "1px"; pixel.style.overflow = "hidden"; var topMaxRadius = Math.max(this.settings["tr"].radius, this.settings["tl"].radius); if(image == -1 && this.backgroundImage != "") +{ pixel.style.backgroundImage = this.backgroundImage; pixel.style.backgroundPosition = "-" + (this.boxWidth - (cornerRadius - intx) + this.borderWidth) + "px -" + ((this.boxHeight + topMaxRadius + inty) -this.borderWidth) + "px";} +else +{ pixel.style.backgroundColor = colour;} +if (transAmount != 100) +setOpacity(pixel, transAmount); pixel.style.top = inty + "px"; pixel.style.left = intx + "px"; newCorner.appendChild(pixel);} +} +function insertAfter(parent, node, referenceNode) +{ parent.insertBefore(node, referenceNode.nextSibling);} +function BlendColour(Col1, Col2, Col1Fraction) +{ var red1 = parseInt(Col1.substr(1,2),16); var green1 = parseInt(Col1.substr(3,2),16); var blue1 = parseInt(Col1.substr(5,2),16); var red2 = parseInt(Col2.substr(1,2),16); var green2 = parseInt(Col2.substr(3,2),16); var blue2 = parseInt(Col2.substr(5,2),16); if(Col1Fraction > 1 || Col1Fraction < 0) Col1Fraction = 1; var endRed = Math.round((red1 * Col1Fraction) + (red2 * (1 - Col1Fraction))); if(endRed > 255) endRed = 255; if(endRed < 0) endRed = 0; var endGreen = Math.round((green1 * Col1Fraction) + (green2 * (1 - Col1Fraction))); if(endGreen > 255) endGreen = 255; if(endGreen < 0) endGreen = 0; var endBlue = Math.round((blue1 * Col1Fraction) + (blue2 * (1 - Col1Fraction))); if(endBlue > 255) endBlue = 255; if(endBlue < 0) endBlue = 0; return "#" + IntToHex(endRed)+ IntToHex(endGreen)+ IntToHex(endBlue);} +function IntToHex(strNum) +{ base = strNum / 16; rem = strNum % 16; base = base - (rem / 16); baseS = MakeHex(base); remS = MakeHex(rem); return baseS + '' + remS;} +function MakeHex(x) +{ if((x >= 0) && (x <= 9)) +{ return x;} +else +{ switch(x) +{ case 10: return "A"; case 11: return "B"; case 12: return "C"; case 13: return "D"; case 14: return "E"; case 15: return "F";} +} +} +function pixelFraction(x, y, r) +{ var pixelfraction = 0; var xvalues = new Array(1); var yvalues = new Array(1); var point = 0; var whatsides = ""; var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x,2))); if ((intersect >= y) && (intersect < (y+1))) +{ whatsides = "Left"; xvalues[point] = 0; yvalues[point] = intersect - y; point = point + 1;} +var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y+1,2))); if ((intersect >= x) && (intersect < (x+1))) +{ whatsides = whatsides + "Top"; xvalues[point] = intersect - x; yvalues[point] = 1; point = point + 1;} +var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x+1,2))); if ((intersect >= y) && (intersect < (y+1))) +{ whatsides = whatsides + "Right"; xvalues[point] = 1; yvalues[point] = intersect - y; point = point + 1;} +var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y,2))); if ((intersect >= x) && (intersect < (x+1))) +{ whatsides = whatsides + "Bottom"; xvalues[point] = intersect - x; yvalues[point] = 0;} +switch (whatsides) +{ case "LeftRight": +pixelfraction = Math.min(yvalues[0],yvalues[1]) + ((Math.max(yvalues[0],yvalues[1]) - Math.min(yvalues[0],yvalues[1]))/2); break; case "TopRight": +pixelfraction = 1-(((1-xvalues[0])*(1-yvalues[1]))/2); break; case "TopBottom": +pixelfraction = Math.min(xvalues[0],xvalues[1]) + ((Math.max(xvalues[0],xvalues[1]) - Math.min(xvalues[0],xvalues[1]))/2); break; case "LeftBottom": +pixelfraction = (yvalues[0]*xvalues[1])/2; break; default: +pixelfraction = 1;} +return pixelfraction;} +function rgb2Hex(rgbColour) +{ try{ var rgbArray = rgb2Array(rgbColour); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); var hexColour = "#" + IntToHex(red) + IntToHex(green) + IntToHex(blue);} +catch(e){ alert("There was an error converting the RGB value to Hexadecimal in function rgb2Hex");} +return hexColour;} +function rgb2Array(rgbColour) +{ var rgbValues = rgbColour.substring(4, rgbColour.indexOf(")")); var rgbArray = rgbValues.split(", "); return rgbArray;} +function setOpacity(obj, opacity) +{ opacity = (opacity == 100)?99.999:opacity; if(isSafari && obj.tagName != "IFRAME") +{ var rgbArray = rgb2Array(obj.style.backgroundColor); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); obj.style.backgroundColor = "rgba(" + red + ", " + green + ", " + blue + ", " + opacity/100 + ")";} +else if(typeof(obj.style.opacity) != "undefined") +{ obj.style.opacity = opacity/100;} +else if(typeof(obj.style.MozOpacity) != "undefined") +{ obj.style.MozOpacity = opacity/100;} +else if(typeof(obj.style.filter) != "undefined") +{ obj.style.filter = "alpha(opacity:" + opacity + ")";} +else if(typeof(obj.style.KHTMLOpacity) != "undefined") +{ obj.style.KHTMLOpacity = opacity/100;} +} +function inArray(array, value) +{ for(var i = 0; i < array.length; i++){ if (array[i] === value) return i;} +return false;} +function inArrayKey(array, value) +{ for(key in array){ if(key === value) return true;} +return false;} +function addEvent(elm, evType, fn, useCapture) { if (elm.addEventListener) { elm.addEventListener(evType, fn, useCapture); return true;} +else if (elm.attachEvent) { var r = elm.attachEvent('on' + evType, fn); return r;} +else { elm['on' + evType] = fn;} +} +function removeEvent(obj, evType, fn, useCapture){ if (obj.removeEventListener){ obj.removeEventListener(evType, fn, useCapture); return true;} else if (obj.detachEvent){ var r = obj.detachEvent("on"+evType, fn); return r;} else { alert("Handler could not be removed");} +} +function format_colour(colour) +{ var returnColour = "#ffffff"; if(colour != "" && colour != "transparent") +{ if(colour.substr(0, 3) == "rgb") +{ returnColour = rgb2Hex(colour);} +else if(colour.length == 4) +{ returnColour = "#" + colour.substring(1, 2) + colour.substring(1, 2) + colour.substring(2, 3) + colour.substring(2, 3) + colour.substring(3, 4) + colour.substring(3, 4);} +else +{ returnColour = colour;} +} +return returnColour;} +function get_style(obj, property, propertyNS) +{ try +{ if(obj.currentStyle) +{ var returnVal = eval("obj.currentStyle." + property);} +else +{ if(isSafari && obj.style.display == "none") +{ obj.style.display = ""; var wasHidden = true;} +var returnVal = document.defaultView.getComputedStyle(obj, '').getPropertyValue(propertyNS); if(isSafari && wasHidden) +{ obj.style.display = "none";} +} +} +catch(e) +{ } +return returnVal;} +function getElementsByClass(searchClass, node, tag) +{ var classElements = new Array(); if(node == null) +node = document; if(tag == null) +tag = '*'; var els = node.getElementsByTagName(tag); var elsLen = els.length; var pattern = new RegExp("(^|\s)"+searchClass+"(\s|$)"); for (i = 0, j = 0; i < elsLen; i++) +{ if(pattern.test(els[i].className)) +{ classElements[j] = els[i]; j++;} +} +return classElements;} +function newCurvyError(errorMessage) +{ return new Error("curvyCorners Error:\n" + errorMessage) +} diff --git a/vendor/gems/polyglot-0.2.5/website/stylesheets/screen.css b/vendor/gems/polyglot-0.2.5/website/stylesheets/screen.css new file mode 100755 index 0000000..2c84cd0 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/website/stylesheets/screen.css @@ -0,0 +1,138 @@ +body { + background-color: #E1D1F1; + font-family: "Georgia", sans-serif; + font-size: 16px; + line-height: 1.6em; + padding: 1.6em 0 0 0; + color: #333; +} +h1, h2, h3, h4, h5, h6 { + color: #444; +} +h1 { + font-family: sans-serif; + font-weight: normal; + font-size: 4em; + line-height: 0.8em; + letter-spacing: -0.1ex; + margin: 5px; +} +li { + padding: 0; + margin: 0; + list-style-type: square; +} +a { + color: #5E5AFF; + background-color: #DAC; + font-weight: normal; + text-decoration: underline; +} +blockquote { + font-size: 90%; + font-style: italic; + border-left: 1px solid #111; + padding-left: 1em; +} +.caps { + font-size: 80%; +} + +#main { + width: 45em; + padding: 0; + margin: 0 auto; +} +.coda { + text-align: right; + color: #77f; + font-size: smaller; +} + +table { + font-size: 90%; + line-height: 1.4em; + color: #ff8; + background-color: #111; + padding: 2px 10px 2px 10px; + border-style: dashed; +} + +th { + color: #fff; +} + +td { + padding: 2px 10px 2px 10px; +} + +.success { + color: #0CC52B; +} + +.failed { + color: #E90A1B; +} + +.unknown { + color: #995000; +} +pre, code { + font-family: monospace; + font-size: 90%; + line-height: 1.4em; + color: #ff8; + background-color: #111; + padding: 2px 10px 2px 10px; +} +.comment { color: #aaa; font-style: italic; } +.keyword { color: #eff; font-weight: bold; } +.punct { color: #eee; font-weight: bold; } +.symbol { color: #0bb; } +.string { color: #6b4; } +.ident { color: #ff8; } +.constant { color: #66f; } +.regex { color: #ec6; } +.number { color: #F99; } +.expr { color: #227; } + +#version { + float: right; + text-align: right; + font-family: sans-serif; + font-weight: normal; + background-color: #B3ABFF; + color: #141331; + padding: 15px 20px 10px 20px; + margin: 0 auto; + margin-top: 15px; + border: 3px solid #141331; +} + +#version .numbers { + display: block; + font-size: 4em; + line-height: 0.8em; + letter-spacing: -0.1ex; + margin-bottom: 15px; +} + +#version p { + text-decoration: none; + color: #141331; + background-color: #B3ABFF; + margin: 0; + padding: 0; +} + +#version a { + text-decoration: none; + color: #141331; + background-color: #B3ABFF; +} + +.clickable { + cursor: pointer; + cursor: hand; +} + diff --git a/vendor/gems/polyglot-0.2.5/website/template.rhtml b/vendor/gems/polyglot-0.2.5/website/template.rhtml new file mode 100755 index 0000000..70ea688 --- /dev/null +++ b/vendor/gems/polyglot-0.2.5/website/template.rhtml @@ -0,0 +1,48 @@ + + + + + + + <%= title %> + + + + + + +
+ +

<%= title %>

+
+

Get Version

+ <%= version %> +
+ <%= body %> +

+ Clifford Heath, <%= modified.pretty %>
+ Theme extended from Paul Battley +

+
+ + + + + diff --git a/vendor/gems/treetop-1.2.5/README b/vendor/gems/treetop-1.2.5/README new file mode 100755 index 0000000..834867c --- /dev/null +++ b/vendor/gems/treetop-1.2.5/README @@ -0,0 +1,164 @@ +Tutorial +======== +Languages can be split into two components, their *syntax* and their *semantics*. It's your understanding of English syntax that tells you the stream of words "Sleep furiously green ideas colorless" is not a valid sentence. Semantics is deeper. Even if we rearrange the above sentence to be "Colorless green ideas sleep furiously", which is syntactically correct, it remains nonsensical on a semantic level. With Treetop, you'll be dealing with languages that are much simpler than English, but these basic concepts apply. Your programs will need to address both the syntax and the semantics of the languages they interpret. + +Treetop equips you with powerful tools for each of these two aspects of interpreter writing. You'll describe the syntax of your language with a *parsing expression grammar*. From this description, Treetop will generate a Ruby parser that transforms streams of characters written into your language into *abstract syntax trees* representing their structure. You'll then describe the semantics of your language in Ruby by defining methods on the syntax trees the parser generates. + +Parsing Expression Grammars, The Basics +======================================= +The first step in using Treetop is defining a grammar in a file with the `.treetop` extension. Here's a grammar that's useless because it's empty: + + # my_grammar.treetop + grammar MyGrammar + end + +Next, you start filling your grammar with rules. Each rule associates a name with a parsing expression, like the following: + + # my_grammar.treetop + # You can use a .tt extension instead if you wish + grammar MyGrammar + rule hello + 'hello chomsky' + end + end + +The first rule becomes the *root* of the grammar, causing its expression to be matched when a parser for the grammar is fed a string. The above grammar can now be used in a Ruby program. Notice how a string matching the first rule parses successfully, but a second nonmatching string does not. + + # use_grammar.rb + require 'rubygems' + require 'treetop' + Treetop.load 'my_grammar' + # or just: + # require 'my_grammar' # This works because Polyglot hooks "require" to find and load Treetop files + + parser = MyGrammarParser.new + puts parser.parse('hello chomsky') # => Treetop::Runtime::SyntaxNode + puts parser.parse('silly generativists!') # => nil + +Users of *regular expressions* will find parsing expressions familiar. They share the same basic purpose, matching strings against patterns. However, parsing expressions can recognize a broader category of languages than their less expressive brethren. Before we get into demonstrating that, lets cover some basics. At first parsing expressions won't seem much different. Trust that they are. + +Terminal Symbols +---------------- +The expression in the grammar above is a terminal symbol. It will only match a string that matches it exactly. There are two other kinds of terminal symbols, which we'll revisit later. Terminals are called *atomic expressions* because they aren't composed of smaller expressions. + +Ordered Choices +--------------- +Ordered choices are *composite expressions*, which allow for any of several subexpressions to be matched. These should be familiar from regular expressions, but in parsing expressions, they are delimited by the `/` character. Its important to note that the choices are prioritized in the order they appear. If an earlier expression is matched, no subsequent expressions are tried. Here's an example: + + # my_grammar.treetop + grammar MyGrammar + rule hello + 'hello chomsky' / 'hello lambek' + end + end + + # fragment of use_grammar.rb + puts parser.parse('hello chomsky') # => Treetop::Runtime::SyntaxNode + puts parser.parse('hello lambek') # => Treetop::Runtime::SyntaxNode + puts parser.parse('silly generativists!') # => nil + +Note that once a choice rule has matched the text using a particular alternative at a particular location in the input and hence has succeeded, that choice will never be reconsidered, even if the chosen alternative causes another rule to fail where a later alternative wouldn't have. It's always a later alternative, since the first to succeed is final - why keep looking when you've found what you wanted? This is a feature of PEG parsers that you need to understand if you're going to succeed in using Treetop. In order to memoize success and failures, such decisions cannot be reversed. Luckily Treetop provides a variety of clever ways you can tell it to avoid making the wrong decisions. But more on that later. + +Sequences +--------- +Sequences are composed of other parsing expressions separated by spaces. Using sequences, we can tighten up the above grammar. + + # my_grammar.treetop + grammar MyGrammar + rule hello + 'hello ' ('chomsky' / 'lambek') + end + end + +Note the use of parentheses to override the default precedence rules, which bind sequences more tightly than choices. + +Once the whole sequence has been matched, the result is memoized and the details of the match will not be reconsidered for that location in the input. + +Nonterminal Symbols +------------------- +Here we leave regular expressions behind. Nonterminals allow expressions to refer to other expressions by name. A trivial use of this facility would allow us to make the above grammar more readable should the list of names grow longer. + + # my_grammar.treetop + grammar MyGrammar + rule hello + 'hello ' linguist + end + + rule linguist + 'chomsky' / 'lambek' / 'jacobsen' / 'frege' + end + end + +The true power of this facility, however, is unleashed when writing *recursive expressions*. Here is a self-referential expression that can match any number of open parentheses followed by any number of closed parentheses. This is theoretically impossible with regular expressions due to the *pumping lemma*. + + # parentheses.treetop + grammar Parentheses + rule parens + '(' parens ')' / '' + end + end + + +The `parens` expression simply states that a `parens` is a set of parentheses surrounding another `parens` expression or, if that doesn't match, the empty string. If you are uncomfortable with recursion, its time to get comfortable, because it is the basis of language. Here's a tip: Don't try and imagine the parser circling round and round through the same rule. Instead, imagine the rule is *already* defined while you are defining it. If you imagine that `parens` already matches a string of matching parentheses, then its easy to think of `parens` as an open and closing parentheses around another set of matching parentheses, which conveniently, you happen to be defining. You know that `parens` is supposed to represent a string of matched parentheses, so trust in that meaning, even if you haven't fully implemented it yet. + +Repetition +---------- +Any item in a rule may be followed by a '+' or a '*' character, signifying one-or-more and zero-or-more occurrences of that item. Beware though; the match is greedy, and if it matches too many items and causes subsequent items in the sequence to fail, the number matched will never be reconsidered. Here's a simple example of a rule that will never succeed: + + # toogreedy.treetop + grammar TooGreedy + rule a_s + 'a'* 'a' + end + end + +The 'a'* will always eat up any 'a's that follow, and the subsequent 'a' will find none there, so the whole rule will fail. You might need to use lookahead to avoid matching too much. + +Negative Lookahead +------------------ + +When you need to ensure that the following item *doesn't* match in some case where it might otherwise, you can use negat!ve lookahead, which is an item preceeded by a ! - here's an example: + + # postcondition.treetop + grammar PostCondition + rule conditional_sentence + ( !conditional_keyword word )+ conditional_keyword [ \t]+ word* + end + + rule word + ([a-zA-Z]+ [ \t]+) + end + + rule conditional_keyword + 'if' / 'while' / 'until' + end + end + +Even though the rule `word` would match any of the conditional keywords, the first words of a conditional_sentence must not be conditional_keywords. The negative lookahead prevents that matching, and prevents the repetition from matching too much input. Note that the lookahead may be a grammar rule of any complexity, including one that isn't used elsewhere in your grammar. + +Positive lookahead +------------------ + +Sometimes you want an item to match, but only if the *following* text would match some pattern. You don't want to consume that following text, but if it's not there, you want this rule to fail. You can append a positive lookahead like this to a rule by appending the lookahead rule preceeded by an & character. + + + +Features to cover in the talk +============================= + +* Treetop files +* Grammar definition +* Rules +* Loading a grammar +* Compiling a grammar with the `tt` command +* Accessing a parser for the grammar from Ruby +* Parsing Expressions of all kinds +? Left recursion and factorization + - Here I can talk about function application, discussing how the operator + could be an arbitrary expression +* Inline node class eval blocks +* Node class declarations +* Labels +* Use of super within within labels +* Grammar composition with include +* Use of super with grammar composition diff --git a/vendor/gems/treetop-1.2.5/Rakefile b/vendor/gems/treetop-1.2.5/Rakefile new file mode 100755 index 0000000..7e1e464 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/Rakefile @@ -0,0 +1,20 @@ +dir = File.dirname(__FILE__) +require 'rubygems' +require 'rake' +$LOAD_PATH.unshift(File.join(dir, 'vendor', 'rspec', 'lib')) +require 'spec/rake/spectask' + +Gem::manage_gems +require 'rake/gempackagetask' + +task :default => :spec + +Spec::Rake::SpecTask.new do |t| + t.pattern = 'spec/**/*spec.rb' +end + +load "./treetop.gemspec" + +Rake::GemPackageTask.new($gemspec) do |pkg| + pkg.need_tar = true +end diff --git a/vendor/gems/treetop-1.2.5/bin/tt b/vendor/gems/treetop-1.2.5/bin/tt new file mode 100755 index 0000000..e4d7e21 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/bin/tt @@ -0,0 +1,28 @@ +#!/usr/bin/env ruby +require 'rubygems' +gem 'treetop' + +$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib")) +require 'treetop' + +if ARGV.empty? + puts "Usage:\n\ntt foo.treetop bar.treetop ...\n or\ntt foo.treetop -o alternate_name.rb\n\n" + exit +end + +compiler = Treetop::Compiler::GrammarCompiler.new + +while !ARGV.empty? + treetop_file = ARGV.shift + if !File.exist?(treetop_file) + puts "Error: file '#{treetop_file}' doesn't exist\n\n" + exit(2) + end + if ARGV.size >= 2 && ARGV[1] == '-o' + ARGV.shift # explicit output file name option + compiler.compile(treetop_file, ARGV.shift) + else + # list of input files option + compiler.compile(treetop_file) + end +end diff --git a/vendor/gems/treetop-1.2.5/doc/contributing_and_planned_features.markdown b/vendor/gems/treetop-1.2.5/doc/contributing_and_planned_features.markdown new file mode 100755 index 0000000..e3d4ab5 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/doc/contributing_and_planned_features.markdown @@ -0,0 +1,103 @@ +#Google Group +I've created a Google Group as a better place to organize discussion and development. +treetop-dev@google-groups.com + +#Contributing +Visit the Treetop repository page on GitHub in your browser for more information about checking out the source code. + +I like to try Rubinius's policy regarding commit rights. If you submit one patch worth integrating, I'll give you commit rights. We'll see how this goes, but I think it's a good policy. + + +##Getting Started with the Code +Treetop compiler is interesting in that it is implemented in itself. Its functionality revolves around `metagrammar.treetop`, which specifies the grammar for Treetop grammars. I took a hybrid approach with regard to definition of methods on syntax nodes in the metagrammar. Methods that are more syntactic in nature, like those that provide access to elements of the syntax tree, are often defined inline, directly in the grammar. More semantic methods are defined in custom node classes. + +Iterating on the metagrammar is tricky. The current testing strategy uses the last stable version of Treetop to parse the version under test. Then the version under test is used to parse and functionally test the various pieces of syntax it should recognize and translate to Ruby. As you change `metagrammar.treetop` and its associated node classes, note that the node classes you are changing are also used to support the previous stable version of the metagrammar, so must be kept backward compatible until such time as a new stable version can be produced to replace it. + +##Tests +Most of the compiler's tests are functional in nature. The grammar under test is used to parse and compile piece of sample code. Then I attempt to parse input with the compiled output and test its results. + +#What Needs to be Done +##Small Stuff +* Improve the `tt` command line tool to allow `.treetop` extensions to be elided in its arguments. +* Generate and load temp files with `Treetop.load` rather than evaluating strings to improve stack trace readability. +* Allow `do/end` style blocks as well as curly brace blocks. This was originally omitted because I thought it would be confusing. It probably isn't. + +##Big Stuff +####Transient Expressions +Currently, every parsing expression instantiates a syntax node. This includes even very simple parsing expressions, like single characters. It is probably unnecessary for every single expression in the parse to correspond to its own syntax node, so much savings could be garnered from a transient declaration that instructs the parser only to attempt a match without instantiating nodes. + +###Generate Rule Implementations in C +Parsing expressions are currently compiled into simple Ruby source code that comprises the body of parsing rules, which are translated into Ruby methods. The generator could produce C instead of Ruby in the body of these method implementations. + +###Global Parsing State and Semantic Backtrack Triggering +Some programming language grammars are not entirely context-free, requiring that global state dictate the behavior of the parser in certain circumstances. Treetop does not currently expose explicit parser control to the grammar writer, and instead automatically constructs the syntax tree for them. A means of semantic parser control compatible with this approach would involve callback methods defined on parsing nodes. Each time a node is successfully parsed it will be given an opportunity to set global state and optionally trigger a parse failure on _extrasyntactic_ grounds. Nodes will probably need to define an additional method that undoes their changes to global state when there is a parse failure and they are backtracked. + +Here is a sketch of the potential utility of such mechanisms. Consider the structure of YAML, which uses indentation to indicate block structure. + + level_1: + level_2a: + level_2b: + level_3a: + level_2c: + +Imagine a grammar like the following: + + rule yaml_element + name ':' block + / + name ':' value + end + + rule block + indent yaml_elements outdent + end + + rule yaml_elements + yaml_element (samedent yaml_element)* + end + + rule samedent + newline spaces { + def after_success(parser_state) + spaces.length == parser_state.indent_level + end + } + end + + rule indent + newline spaces { + def after_success(parser_state) + if spaces.length == parser_state.indent_level + 2 + parser_state.indent_level += 2 + true + else + false # fail the parse on extrasyntactic grounds + end + end + + def undo_success(parser_state) + parser_state.indent_level -= 2 + end + } + end + + rule outdent + newline spaces { + def after_success(parser_state) + if spaces.length == parser_state.indent_level - 2 + parser_state.indent_level -= 2 + true + else + false # fail the parse on extrasyntactic grounds + end + end + + def undo_success(parser_state) + parser_state.indent_level += 2 + end + } + end + +In this case a block will be detected only if a change in indentation warrants it. Note that this change in the state of indentation must be undone if a subsequent failure causes this node not to ultimately be incorporated into a successful result. + +I am by no means sure that the above sketch is free of problems, or even that this overall strategy is sound, but it seems like a promising path. diff --git a/vendor/gems/treetop-1.2.5/doc/grammar_composition.markdown b/vendor/gems/treetop-1.2.5/doc/grammar_composition.markdown new file mode 100755 index 0000000..a1704ed --- /dev/null +++ b/vendor/gems/treetop-1.2.5/doc/grammar_composition.markdown @@ -0,0 +1,65 @@ +#Grammar Composition +A unique property of parsing expression grammars is that they are _closed under composition_. This means that when you compose two grammars they yield another grammar that can be composed yet again. This is a radical departure from parsing frameworks require on lexical scanning, which makes compositionally impossible. Treetop's facilities for composition are built upon those of Ruby. + +##The Mapping of Treetop Constructs to Ruby Constructs +When Treetop compiles a grammar definition, it produces a module and a class. The module contains methods implementing all of the rules defined in the grammar. The generated class is a subclass of Treetop::Runtime::CompiledParser and includes the module. For example: + + grammar Foo + ... + end + +results in a Ruby module named `Foo` and a Ruby class named `FooParser` that `include`s the `Foo` module. + +##Using Mixin Semantics to Compose Grammars +Because grammars are just modules, they can be mixed into one another. This enables grammars to share rules. + + grammar A + rule a + 'a' + end + end + + grammar B + include A + + rule ab + a 'b' + end + end + +Grammar `B` above references rule `a` defined in a separate grammar that it includes. Because module inclusion places modules in the ancestor chain, rules may also be overridden with the use of the `super` keyword accessing the overridden rule. + + grammar A + rule a + 'a' + end + end + + grammar B + include A + + rule a + super / 'b' + end + end + +Now rule `a` in grammar `B` matches either `'a'` or `'b'`. + +##Motivation +Imagine a grammar for Ruby that took account of SQL queries embedded in strings within the language. That could be achieved by combining two existing grammars. + + grammar RubyPlusSQL + include Ruby + include SQL + + rule expression + ruby_expression + end + + rule ruby_string + ruby_quote sql_expression ruby_quote / ruby_string + end + end + +##Work to be Done +It has become clear that the include facility in grammars would be more useful if it had the ability to name prefix all rules from the included grammar to avoid collision. This is a planned but currently unimplemented feature. \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/doc/index.markdown b/vendor/gems/treetop-1.2.5/doc/index.markdown new file mode 100755 index 0000000..dfebfdf --- /dev/null +++ b/vendor/gems/treetop-1.2.5/doc/index.markdown @@ -0,0 +1,90 @@ +

+ +Treetop is a language for describing languages. Combining the elegance of Ruby with cutting-edge parsing expression grammars, it helps you analyze syntax with revolutionarily ease. + +

+ + sudo gem install treetop + +#Intuitive Grammar Specifications +Parsing expression grammars (PEGs) are simple to write and easy to maintain. They are a simple but powerful generalization of regular expressions that are easier to work with than the LALR or LR-1 grammars of traditional parser generators. There's no need for a tokenization phase, and _lookahead assertions_ can be used for a limited degree of context-sensitivity. Here's an extremely simple Treetop grammar that matches a subset of arithmetic, respecting operator precedence: + + grammar Arithmetic + rule additive + multitive '+' additive / multitive + end + + rule multitive + primary '*' multitive / primary + end + + rule primary + '(' additive ')' / number + end + + rule number + [1-9] [0-9]* + end + end + + +#Syntax-Oriented Programming +Rather than implementing semantic actions that construct parse trees, Treetop lets you define methods on trees that it constructs for you automatically. You can define these methods directly within the grammar... + + grammar Arithmetic + rule additive + multitive '+' additive { + def value + multitive.value + additive.value + end + } + / + multitive + end + + # other rules below ... + end + +...or associate rules with classes of nodes you wish your parsers to instantiate upon matching a rule. + + grammar Arithmetic + rule additive + multitive '+' additive + / + multitive + end + + # other rules below ... + end + + +#Reusable, Composable Language Descriptions +Because PEGs are closed under composition, Treetop grammars can be treated like Ruby modules. You can mix them into one another and override rules with access to the `super` keyword. You can break large grammars down into coherent units or make your language's syntax modular. This is especially useful if you want other programmers to be able to reuse your work. + + grammar RubyWithEmbeddedSQL + include SQL + + rule string + quote sql_expression quote / super + end + end + + +#Acknowledgements + + + + +First, thank you to my employer Rob Mee of Pivotal Labs for funding a substantial portion of Treetop's development. He gets it. + + +I'd also like to thank: + +* Damon McCormick for several hours of pair programming. +* Nick Kallen for lots of well-considered feedback and a few afternoons of programming. +* Brian Takita for a night of pair programming. +* Eliot Miranda for urging me rewrite as a compiler right away rather than putting it off. +* Ryan Davis and Eric Hodel for hurting my code. +* Dav Yaginuma for kicking me into action on my idea. +* Bryan Ford for his seminal work on Packrat Parsers. +* The editors of Lambda the Ultimate, where I discovered parsing expression grammars. \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/doc/pitfalls_and_advanced_techniques.markdown b/vendor/gems/treetop-1.2.5/doc/pitfalls_and_advanced_techniques.markdown new file mode 100755 index 0000000..3648f33 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/doc/pitfalls_and_advanced_techniques.markdown @@ -0,0 +1,51 @@ +#Pitfalls +##Left Recursion +An weakness shared by all recursive descent parsers is the inability to parse left-recursive rules. Consider the following rule: + + rule left_recursive + left_recursive 'a' / 'a' + end + +Logically it should match a list of 'a' characters. But it never consumes anything, because attempting to recognize `left_recursive` begins by attempting to recognize `left_recursive`, and so goes an infinite recursion. There's always a way to eliminate these types of structures from your grammar. There's a mechanistic transformation called _left factorization_ that can eliminate it, but it isn't always pretty, especially in combination with automatically constructed syntax trees. So far, I have found more thoughtful ways around the problem. For instance, in the interpreter example I interpret inherently left-recursive function application right recursively in syntax, then correct the directionality in my semantic interpretation. You may have to be clever. + +#Advanced Techniques +Here are a few interesting problems I've encountered. I figure sharing them may give you insight into how these types of issues are addressed with the tools of parsing expressions. + +##Matching a String + + rule string + '"' (!'"' . / '\"')* '"' + end + +This expression says: Match a quote, then zero or more of any character but a quote or an escaped quote followed by a quote. Lookahead assertions are essential for these types of problems. + +##Matching Nested Structures With Non-Unique Delimeters +Say I want to parse a diabolical wiki syntax in which the following interpretations apply. + + ** *hello* ** --> hello + * **hello** * --> hello + + rule strong + '**' (em / !'*' . / '\*')+ '**' + end + + rule em + '**' (strong / !'*' . / '\*')+ '**' + end + +Emphasized text is allowed within strong text by virtue of `em` being the first alternative. Since `em` will only successfully parse if a matching `*` is found, it is permitted, but other than that, no `*` characters are allowed unless they are escaped. + +##Matching a Keyword But Not Words Prefixed Therewith +Say I want to consider a given string a characters only when it occurs in isolation. Lets use the `end` keyword as an example. We don't want the prefix of `'enders_game'` to be considered a keyword. A naiive implementation might be the following. + + rule end_keyword + 'end' &space + end + +This says that `'end'` must be followed by a space, but this space is not consumed as part of the matching of `keyword`. This works in most cases, but is actually incorrect. What if `end` occurs at the end of the buffer? In that case, it occurs in isolation but will not match the above expression. What we really mean is that `'end'` cannot be followed by a _non-space_ character. + + rule end_keyword + 'end' !(!' ' .) + end + +In general, when the syntax gets tough, it helps to focus on what you really mean. A keyword is a character not followed by another character that isn't a space. \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/doc/semantic_interpretation.markdown b/vendor/gems/treetop-1.2.5/doc/semantic_interpretation.markdown new file mode 100755 index 0000000..e8245d5 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/doc/semantic_interpretation.markdown @@ -0,0 +1,189 @@ +#Semantic Interpretation +Lets use the below grammar as an example. It describes parentheses wrapping a single character to an arbitrary depth. + + grammar ParenLanguage + rule parenthesized_letter + '(' parenthesized_letter ')' + / + [a-z] + end + end + +Matches: + +* `'a'` +* `'(a)'` +* `'((a))'` +* etc. + + +Output from a parser for this grammar looks like this: + +![Tree Returned By ParenLanguageParser](./images/paren_language_output.png) + +This is a parse tree whose nodes are instances of `Treetop::Runtime::SyntaxNode`. What if we could define methods on these node objects? We would then have an object-oriented program whose structure corresponded to the structure of our language. Treetop provides two techniques for doing just this. + +##Associating Methods with Node-Instantiating Expressions +Sequences and all types of terminals are node-instantiating expressions. When they match, they create instances of `Treetop::Runtime::SyntaxNode`. Methods can be added to these nodes in the following ways: + +###Inline Method Definition +Methods can be added to the nodes instantiated by the successful match of an expression + + grammar ParenLanguage + rule parenthesized_letter + '(' parenthesized_letter ')' { + def depth + parenthesized_letter.depth + 1 + end + } + / + [a-z] { + def depth + 0 + end + } + end + end + +Note that each alternative expression is followed by a block containing a method definition. A `depth` method is defined on both expressions. The recursive `depth` method defined in the block following the first expression determines the depth of the nested parentheses and adds one two it. The base case is implemented in the block following the second expression; a single character has a depth of 0. + + +###Custom `SyntaxNode` Subclass Declarations +You can instruct the parser to instantiate a custom subclass of Treetop::Runtime::SyntaxNode for an expression by following it by the name of that class enclosed in angle brackets (`<>`). The above inline method definitions could have been moved out into a single class like so. + + # in .treetop file + grammar ParenLanguage + rule parenthesized_letter + '(' parenthesized_letter ')' + / + [a-z] + end + end + + # in separate .rb file + class ParenNode < Treetop::Runtime::SyntaxNode + def depth + if nonterminal? + parenthesized_letter.depth + 1 + else + 0 + end + end + end + +##Automatic Extension of Results +Nonterminal and ordered choice expressions do not instantiate new nodes, but rather pass through nodes that are instantiated by other expressions. They can extend nodes they propagate with anonymous or declared modules, using similar constructs used with expressions that instantiate their own syntax nodes. + +###Extending a Propagated Node with an Anonymous Module + rule parenthesized_letter + ('(' parenthesized_letter ')' / [a-z]) { + def depth + if nonterminal? + parenthesized_letter.depth + 1 + else + 0 + end + end + } + end + +The parenthesized choice above can result in a node matching either of the two choices. Than node will be extended with methods defined in the subsequent block. Note that a choice must always be parenthesized to be associated with a following block. + +###Extending A Propagated Node with a Declared Module + # in .treetop file + rule parenthesized_letter + ('(' parenthesized_letter ')' / [a-z]) + end + + # in separate .rb file + module ParenNode + def depth + if nonterminal? + parenthesized_letter.depth + 1 + else + 0 + end + end + end + +Here the result is extended with the `ParenNode` module. Note the previous example for node-instantiating expressions, the constant in the declaration must be a module because the result is extended with it. + +##Automatically-Defined Element Accessor Methods +###Default Accessors +Nodes instantiated upon the matching of sequences have methods automatically defined for any nonterminals in the sequence. + + rule abc + a b c { + def to_s + a.to_s + b.to_s + c.to_s + end + } + end + +In the above code, the `to_s` method calls automatically-defined element accessors for the nodes returned by parsing nonterminals `a`, `b`, and `c`. + +###Labels +Subexpressions can be given an explicit label to have an element accessor method defined for them. This is useful in cases of ambiguity between two references to the same nonterminal or when you need to access an unnamed subexpression. + + rule labels + first_letter:[a-z] rest_letters:(', ' letter:[a-z])* { + def letters + [first_letter] + rest_letters.map do |comma_and_letter| + comma_and_letter.letter + end + end + } + end + +The above grammar uses label-derived accessors to determine the letters in a comma-delimited list of letters. The labeled expressions _could_ have been extracted to their own rules, but if they aren't used elsewhere, labels still enable them to be referenced by a name within the expression's methods. + +###Overriding Element Accessors +The module containing automatically defined element accessor methods is an ancestor of the module in which you define your own methods, meaning you can override them with access to the `super` keyword. Here's an example of how this fact can improve the readability of the example above. + + rule labels + first_letter:[a-z] rest_letters:(', ' letter:[a-z])* { + def letters + [first_letter] + rest_letters + end + + def rest_letters + super.map { |comma_and_letter| comma_and_letter.letter } + end + } + end + + +##Methods Available on `Treetop::Runtime::SyntaxNode` + + + + + + + + + + + + + + + + +
+ terminal? + + Was this node produced by the matching of a terminal symbol? +
+ nonterminal? + + Was this node produced by the matching of a nonterminal symbol? +
+ text_value + + The substring of the input represented by this node. +
+ elements + + Available only on nonterminal nodes, returns the nodes parsed by the elements of the matched sequence. +
\ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/doc/site.rb b/vendor/gems/treetop-1.2.5/doc/site.rb new file mode 100755 index 0000000..0fc648e --- /dev/null +++ b/vendor/gems/treetop-1.2.5/doc/site.rb @@ -0,0 +1,110 @@ +require 'rubygems' +require 'erector' +require "#{File.dirname(__FILE__)}/sitegen" + +class Layout < Erector::Widget + def render + html do + head do + link :rel => "stylesheet", + :type => "text/css", + :href => "./screen.css" + + rawtext %( + + + ) + end + + body do + div :id => 'top' do + div :id => 'main_navigation' do + main_navigation + end + end + div :id => 'middle' do + div :id => 'content' do + content + end + end + div :id => 'bottom' do + + end + end + end + end + + def main_navigation + ul do + li { link_to "Documentation", SyntacticRecognition, Documentation } + li { link_to "Contribute", Contribute } + li { link_to "Home", Index } + end + end + + def content + end +end + +class Index < Layout + def content + bluecloth "index.markdown" + end +end + +class Documentation < Layout + abstract + + def content + div :id => 'secondary_navigation' do + ul do + li { link_to 'Syntax', SyntacticRecognition } + li { link_to 'Semantics', SemanticInterpretation } + li { link_to 'Using In Ruby', UsingInRuby } + li { link_to 'Advanced Techniques', PitfallsAndAdvancedTechniques } + end + end + + div :id => 'documentation_content' do + documentation_content + end + end +end + +class SyntacticRecognition < Documentation + def documentation_content + bluecloth "syntactic_recognition.markdown" + end +end + +class SemanticInterpretation < Documentation + def documentation_content + bluecloth "semantic_interpretation.markdown" + end +end + +class UsingInRuby < Documentation + def documentation_content + bluecloth "using_in_ruby.markdown" + end +end + +class PitfallsAndAdvancedTechniques < Documentation + def documentation_content + bluecloth "pitfalls_and_advanced_techniques.markdown" + end +end + + +class Contribute < Layout + def content + bluecloth "contributing_and_planned_features.markdown" + end +end + + +Layout.generate_site \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/doc/sitegen.rb b/vendor/gems/treetop-1.2.5/doc/sitegen.rb new file mode 100755 index 0000000..b7bac1b --- /dev/null +++ b/vendor/gems/treetop-1.2.5/doc/sitegen.rb @@ -0,0 +1,60 @@ +class Layout < Erector::Widget + + class << self + def inherited(page_class) + puts page_class + (@@page_classes ||= []) << page_class + end + + def generate_site + @@page_classes.each do |page_class| + page_class.generate_html unless page_class.abstract? + puts page_class + end + end + + def generate_html + File.open(absolute_path, 'w') do |file| + file.write(new.render) + end + end + + def absolute_path + absolutize(relative_path) + end + + def relative_path + "#{name.gsub('::', '_').underscore}.html" + end + + def absolutize(relative_path) + File.join(File.dirname(__FILE__), "site", relative_path) + end + + def abstract + @abstract = true + end + + def abstract? + @abstract + end + end + + def bluecloth(relative_path) + File.open(File.join(File.dirname(__FILE__), relative_path)) do |file| + rawtext BlueCloth.new(file.read).to_html + end + end + + def absolutize(relative_path) + self.class.absolutize(relative_path) + end + + def link_to(link_text, page_class, section_class=nil) + if instance_of?(page_class) || section_class && is_a?(section_class) + text link_text + else + a link_text, :href => page_class.relative_path + end + end +end diff --git a/vendor/gems/treetop-1.2.5/doc/syntactic_recognition.markdown b/vendor/gems/treetop-1.2.5/doc/syntactic_recognition.markdown new file mode 100755 index 0000000..6c71810 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/doc/syntactic_recognition.markdown @@ -0,0 +1,100 @@ +#Syntactic Recognition +Treetop grammars are written in a custom language based on parsing expression grammars. Literature on the subject of parsing expression grammars is useful in writing Treetop grammars. + +#Grammar Structure +Treetop grammars look like this: + + grammar GrammarName + rule rule_name + ... + end + + rule rule_name + ... + end + + ... + end + +The main keywords are: + +* `grammar` : This introduces a new grammar. It is followed by a constant name to which the grammar will be bound when it is loaded. + +* `rule` : This defines a parsing rule within the grammar. It is followed by a name by which this rule can be referenced within other rules. It is then followed by a parsing expression defining the rule. + +#Parsing Expressions +Each rule associates a name with a _parsing expression_. Parsing expressions are a generalization of vanilla regular expressions. Their key feature is the ability to reference other expressions in the grammar by name. + +##Terminal Symbols +###Strings +Strings are surrounded in double or single quotes and must be matched exactly. + +* `"foo"` +* `'foo'` + +###Character Classes +Character classes are surrounded by brackets. Their semantics are identical to those used in Ruby's regular expressions. + +* `[a-zA-Z]` +* `[0-9]` + +###The Anything Symbol +The anything symbol is represented by a dot (`.`) and matches any single character. + +##Nonterminal Symbols +Nonterminal symbols are unquoted references to other named rules. They are equivalent to an inline substitution of the named expression. + + rule foo + "the dog " bar + end + + rule bar + "jumped" + end + +The above grammar is equivalent to: + + rule foo + "the dog jumped" + end + +##Ordered Choice +Parsers attempt to match ordered choices in left-to-right order, and stop after the first successful match. + + "foobar" / "foo" / "bar" + +Note that if `"foo"` in the above expression came first, `"foobar"` would never be matched. + +##Sequences + +Sequences are a space-separated list of parsing expressions. They have higher precedence than choices, so choices must be parenthesized to be used as the elements of a sequence. + + "foo" "bar" ("baz" / "bop") + +##Zero or More +Parsers will greedily match an expression zero or more times if it is followed by the star (`*`) symbol. + +* `'foo'*` matches the empty string, `"foo"`, `"foofoo"`, etc. + +##One or More +Parsers will greedily match an expression one or more times if it is followed by the star (`+`) symbol. + +* `'foo'+` does not match the empty string, but matches `"foo"`, `"foofoo"`, etc. + +##Optional Expressions +An expression can be declared optional by following it with a question mark (`?`). + +* `'foo'?` matches `"foo"` or the empty string. + +##Lookahead Assertions +Lookahead assertions can be used to give parsing expressions a limited degree of context-sensitivity. The parser will look ahead into the buffer and attempt to match an expression without consuming input. + +###Positive Lookahead Assertion +Preceding an expression with an ampersand `(&)` indicates that it must match, but no input will be consumed in the process of determining whether this is true. + +* `"foo" &"bar"` matches `"foobar"` but only consumes up to the end `"foo"`. It will not match `"foobaz"`. + +###Negative Lookahead Assertion +Preceding an expression with a bang `(!)` indicates that the expression must not match, but no input will be consumed in the process of determining whether this is true. + +* `"foo" !"bar"` matches `"foobaz"` but only consumes up to the end `"foo"`. It will not match `"foobar"`. diff --git a/vendor/gems/treetop-1.2.5/doc/using_in_ruby.markdown b/vendor/gems/treetop-1.2.5/doc/using_in_ruby.markdown new file mode 100755 index 0000000..57382af --- /dev/null +++ b/vendor/gems/treetop-1.2.5/doc/using_in_ruby.markdown @@ -0,0 +1,21 @@ +#Using Treetop Grammars in Ruby +##Using the Command Line Compiler +You can `.treetop` files into Ruby source code with the `tt` command line script. `tt` takes an list of files with a `.treetop` extension and compiles them into `.rb` files of the same name. You can then `require` these files like any other Ruby script. Alternately, you can supply just one `.treetop` file and a `-o` flag to name specify the name of the output file. Improvements to this compilation script are welcome. + + tt foo.treetop bar.treetop + tt foo.treetop -o foogrammar.rb + +##Loading A Grammar Directly +The Polyglot gem makes it possible to load `.treetop` or `.tt` files directly with `require`. This will invoke `Treetop.load`, which automatically compiles the grammar to Ruby and then evaluates the Ruby source. If you are getting errors in methods you define on the syntax tree, try using the command line compiler for better stack trace feedback. A better solution to this issue is in the works. + +##Instantiating and Using Parsers +If a grammar by the name of `Foo` is defined, the compiled Ruby source will define a `FooParser` class. To parse input, create an instance and call its `parse` method with a string. The parser will return the syntax tree of the match or `nil` if there is a failure. + + Treetop.load "arithmetic" + + parser = ArithmeticParser.new + if parser.parse('1+1') + puts 'success' + else + puts 'failure' + end diff --git a/vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic.rb b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic.rb new file mode 100755 index 0000000..8f74129 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic.rb @@ -0,0 +1,551 @@ +module Arithmetic + include Treetop::Runtime + + def root + @root || :expression + end + + def _nt_expression + start_index = index + cached = node_cache[:expression][index] + if cached + @index = cached.interval.end + return cached + end + + i0 = index + r1 = _nt_comparative + if r1.success? + r0 = r1 + else + r2 = _nt_additive + if r2.success? + r0 = r2 + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + end + + node_cache[:expression][start_index] = r0 + + return r0 + end + + module Comparative0 + def operand_1 + elements[0] + end + + def space + elements[1] + end + + def operator + elements[2] + end + + def space + elements[3] + end + + def operand_2 + elements[4] + end + end + + def _nt_comparative + start_index = index + cached = node_cache[:comparative][index] + if cached + @index = cached.interval.end + return cached + end + + i0, s0 = index, [] + r1 = _nt_additive + s0 << r1 + if r1.success? + r2 = _nt_space + s0 << r2 + if r2.success? + r3 = _nt_equality_op + s0 << r3 + if r3.success? + r4 = _nt_space + s0 << r4 + if r4.success? + r5 = _nt_additive + s0 << r5 + end + end + end + end + if s0.last.success? + r0 = (BinaryOperation).new(input, i0...index, s0) + r0.extend(Comparative0) + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + + node_cache[:comparative][start_index] = r0 + + return r0 + end + + module EqualityOp0 + def apply(a, b) + a == b + end + end + + def _nt_equality_op + start_index = index + cached = node_cache[:equality_op][index] + if cached + @index = cached.interval.end + return cached + end + + r0 = parse_terminal('==', SyntaxNode, EqualityOp0) + + node_cache[:equality_op][start_index] = r0 + + return r0 + end + + module Additive0 + def operand_1 + elements[0] + end + + def space + elements[1] + end + + def operator + elements[2] + end + + def space + elements[3] + end + + def operand_2 + elements[4] + end + end + + def _nt_additive + start_index = index + cached = node_cache[:additive][index] + if cached + @index = cached.interval.end + return cached + end + + i0 = index + i1, s1 = index, [] + r2 = _nt_multitive + s1 << r2 + if r2.success? + r3 = _nt_space + s1 << r3 + if r3.success? + r4 = _nt_additive_op + s1 << r4 + if r4.success? + r5 = _nt_space + s1 << r5 + if r5.success? + r6 = _nt_additive + s1 << r6 + end + end + end + end + if s1.last.success? + r1 = (BinaryOperation).new(input, i1...index, s1) + r1.extend(Additive0) + else + self.index = i1 + r1 = ParseFailure.new(input, i1) + end + if r1.success? + r0 = r1 + else + r7 = _nt_multitive + if r7.success? + r0 = r7 + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + end + + node_cache[:additive][start_index] = r0 + + return r0 + end + + module AdditiveOp0 + def apply(a, b) + a + b + end + end + + module AdditiveOp1 + def apply(a, b) + a - b + end + end + + def _nt_additive_op + start_index = index + cached = node_cache[:additive_op][index] + if cached + @index = cached.interval.end + return cached + end + + i0 = index + r1 = parse_terminal('+', SyntaxNode, AdditiveOp0) + if r1.success? + r0 = r1 + else + r2 = parse_terminal('-', SyntaxNode, AdditiveOp1) + if r2.success? + r0 = r2 + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + end + + node_cache[:additive_op][start_index] = r0 + + return r0 + end + + module Multitive0 + def operand_1 + elements[0] + end + + def space + elements[1] + end + + def operator + elements[2] + end + + def space + elements[3] + end + + def operand_2 + elements[4] + end + end + + def _nt_multitive + start_index = index + cached = node_cache[:multitive][index] + if cached + @index = cached.interval.end + return cached + end + + i0 = index + i1, s1 = index, [] + r2 = _nt_primary + s1 << r2 + if r2.success? + r3 = _nt_space + s1 << r3 + if r3.success? + r4 = _nt_multitive_op + s1 << r4 + if r4.success? + r5 = _nt_space + s1 << r5 + if r5.success? + r6 = _nt_multitive + s1 << r6 + end + end + end + end + if s1.last.success? + r1 = (BinaryOperation).new(input, i1...index, s1) + r1.extend(Multitive0) + else + self.index = i1 + r1 = ParseFailure.new(input, i1) + end + if r1.success? + r0 = r1 + else + r7 = _nt_primary + if r7.success? + r0 = r7 + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + end + + node_cache[:multitive][start_index] = r0 + + return r0 + end + + module MultitiveOp0 + def apply(a, b) + a * b + end + end + + module MultitiveOp1 + def apply(a, b) + a / b + end + end + + def _nt_multitive_op + start_index = index + cached = node_cache[:multitive_op][index] + if cached + @index = cached.interval.end + return cached + end + + i0 = index + r1 = parse_terminal('*', SyntaxNode, MultitiveOp0) + if r1.success? + r0 = r1 + else + r2 = parse_terminal('/', SyntaxNode, MultitiveOp1) + if r2.success? + r0 = r2 + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + end + + node_cache[:multitive_op][start_index] = r0 + + return r0 + end + + module Primary0 + def space + elements[1] + end + + def expression + elements[2] + end + + def space + elements[3] + end + + end + + module Primary1 + def eval(env={}) + expression.eval(env) + end + end + + def _nt_primary + start_index = index + cached = node_cache[:primary][index] + if cached + @index = cached.interval.end + return cached + end + + i0 = index + r1 = _nt_variable + if r1.success? + r0 = r1 + else + r2 = _nt_number + if r2.success? + r0 = r2 + else + i3, s3 = index, [] + r4 = parse_terminal('(', SyntaxNode) + s3 << r4 + if r4.success? + r5 = _nt_space + s3 << r5 + if r5.success? + r6 = _nt_expression + s3 << r6 + if r6.success? + r7 = _nt_space + s3 << r7 + if r7.success? + r8 = parse_terminal(')', SyntaxNode) + s3 << r8 + end + end + end + end + if s3.last.success? + r3 = (SyntaxNode).new(input, i3...index, s3) + r3.extend(Primary0) + r3.extend(Primary1) + else + self.index = i3 + r3 = ParseFailure.new(input, i3) + end + if r3.success? + r0 = r3 + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + end + end + + node_cache[:primary][start_index] = r0 + + return r0 + end + + module Variable0 + def eval(env={}) + env[name] + end + + def name + text_value + end + end + + def _nt_variable + start_index = index + cached = node_cache[:variable][index] + if cached + @index = cached.interval.end + return cached + end + + s0, i0 = [], index + loop do + r1 = parse_char_class(/[a-z]/, 'a-z', SyntaxNode) + if r1.success? + s0 << r1 + else + break + end + end + if s0.empty? + self.index = i0 + r0 = ParseFailure.new(input, i0) + else + r0 = SyntaxNode.new(input, i0...index, s0) + r0.extend(Variable0) + end + + node_cache[:variable][start_index] = r0 + + return r0 + end + + module Number0 + end + + module Number1 + def eval(env={}) + text_value.to_i + end + end + + def _nt_number + start_index = index + cached = node_cache[:number][index] + if cached + @index = cached.interval.end + return cached + end + + i0 = index + i1, s1 = index, [] + r2 = parse_char_class(/[1-9]/, '1-9', SyntaxNode) + s1 << r2 + if r2.success? + s3, i3 = [], index + loop do + r4 = parse_char_class(/[0-9]/, '0-9', SyntaxNode) + if r4.success? + s3 << r4 + else + break + end + end + r3 = SyntaxNode.new(input, i3...index, s3) + s1 << r3 + end + if s1.last.success? + r1 = (SyntaxNode).new(input, i1...index, s1) + r1.extend(Number0) + else + self.index = i1 + r1 = ParseFailure.new(input, i1) + end + if r1.success? + r0 = r1 + r0.extend(Number1) + else + r5 = parse_terminal('0', SyntaxNode) + if r5.success? + r0 = r5 + r0.extend(Number1) + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + end + + node_cache[:number][start_index] = r0 + + return r0 + end + + def _nt_space + start_index = index + cached = node_cache[:space][index] + if cached + @index = cached.interval.end + return cached + end + + s0, i0 = [], index + loop do + r1 = parse_terminal(' ', SyntaxNode) + if r1.success? + s0 << r1 + else + break + end + end + r0 = SyntaxNode.new(input, i0...index, s0) + + node_cache[:space][start_index] = r0 + + return r0 + end + +end + +class ArithmeticParser < Treetop::Runtime::CompiledParser + include Arithmetic +end diff --git a/vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic.treetop b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic.treetop new file mode 100755 index 0000000..a54f6e2 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic.treetop @@ -0,0 +1,97 @@ +grammar Arithmetic + rule expression + comparative / additive + end + + rule comparative + operand_1:additive space operator:equality_op space operand_2:additive + end + + rule equality_op + '==' { + def apply(a, b) + a == b + end + } + end + + rule additive + operand_1:multitive + space operator:additive_op space + operand_2:additive + / + multitive + end + + rule additive_op + '+' { + def apply(a, b) + a + b + end + } + / + '-' { + def apply(a, b) + a - b + end + } + end + + rule multitive + operand_1:primary + space operator:multitive_op space + operand_2:multitive + / + primary + end + + rule multitive_op + '*' { + def apply(a, b) + a * b + end + } + / + '/' { + def apply(a, b) + a / b + end + } + end + + rule primary + variable + / + number + / + '(' space expression space ')' { + def eval(env={}) + expression.eval(env) + end + } + end + + rule variable + [a-z]+ { + def eval(env={}) + env[name] + end + + def name + text_value + end + } + end + + rule number + ([1-9] [0-9]* / '0') { + def eval(env={}) + text_value.to_i + end + } + end + + rule space + ' '* + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic_node_classes.rb b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic_node_classes.rb new file mode 100755 index 0000000..63a6012 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic_node_classes.rb @@ -0,0 +1,7 @@ +module Arithmetic + class BinaryOperation < Treetop::Runtime::SyntaxNode + def eval(env={}) + operator.apply(operand_1.eval(env), operand_2.eval(env)) + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic_test.rb b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic_test.rb new file mode 100755 index 0000000..753209c --- /dev/null +++ b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/arithmetic_test.rb @@ -0,0 +1,54 @@ +dir = File.dirname(__FILE__) +require File.expand_path("#{dir}/test_helper") + +require File.expand_path("#{dir}/arithmetic_node_classes") +Treetop.load File.expand_path("#{dir}/arithmetic") + +class ArithmeticParserTest < Test::Unit::TestCase + include ParserTestHelper + + def setup + @parser = ArithmeticParser.new + end + + def test_number + assert_equal 0, parse('0').eval + assert_equal 1, parse('1').eval + assert_equal 123, parse('123').eval + end + + def test_variable + assert_equal 0, parse('x').eval('x' => 0) + assert_equal 3, parse('x').eval('x' => 3) + assert_equal 10, parse('y').eval('y' => 10) + end + + def test_addition + assert_equal 10, parse('x + 5').eval('x' => 5) + end + + def test_subtraction + assert_equal 0, parse('x - 5').eval('x' => 5) + end + + def test_multiplication + assert_equal 6, parse('x * 2').eval('x' => 3) + end + + def test_division + assert_equal 3, parse('x / 2').eval('x' => 6) + end + + def test_order_of_operations + assert_equal 11, parse('1 + 2 * 3 + 4').eval + end + + def test_parentheses + assert_equal 25, parse('(5 + x) * (10 - y)').eval('x' => 0, 'y' => 5) + end + + def test_equality + assert parse('4 == 4').eval + assert !parse('4 == 3').eval + end +end diff --git a/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus new file mode 100755 index 0000000..e69de29 diff --git a/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus.rb b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus.rb new file mode 100755 index 0000000..8b5ae09 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus.rb @@ -0,0 +1,718 @@ +module LambdaCalculus + include Treetop::Runtime + + def root + @root || :program + end + + include Arithmetic + + module Program0 + def space + elements[1] + end + + def expression + elements[2] + end + end + + module Program1 + def expression + elements[0] + end + + def more_expressions + elements[1] + end + end + + module Program2 + def eval(env={}) + env = env.clone + last_eval = nil + expressions.each do |exp| + last_eval = exp.eval(env) + end + last_eval + end + + def expressions + [expression] + more_expressions.elements.map {|elt| elt.expression} + end + end + + def _nt_program + start_index = index + cached = node_cache[:program][index] + if cached + @index = cached.interval.end + return cached + end + + i0, s0 = index, [] + r1 = _nt_expression + s0 << r1 + if r1.success? + s2, i2 = [], index + loop do + i3, s3 = index, [] + r4 = parse_terminal(';', SyntaxNode) + s3 << r4 + if r4.success? + r5 = _nt_space + s3 << r5 + if r5.success? + r6 = _nt_expression + s3 << r6 + end + end + if s3.last.success? + r3 = (SyntaxNode).new(input, i3...index, s3) + r3.extend(Program0) + else + self.index = i3 + r3 = ParseFailure.new(input, i3) + end + if r3.success? + s2 << r3 + else + break + end + end + r2 = SyntaxNode.new(input, i2...index, s2) + s0 << r2 + end + if s0.last.success? + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(Program1) + r0.extend(Program2) + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + + node_cache[:program][start_index] = r0 + + return r0 + end + + def _nt_expression + start_index = index + cached = node_cache[:expression][index] + if cached + @index = cached.interval.end + return cached + end + + i0 = index + r1 = _nt_definition + if r1.success? + r0 = r1 + else + r2 = _nt_conditional + if r2.success? + r0 = r2 + else + r3 = _nt_application + if r3.success? + r0 = r3 + else + r4 = _nt_function + if r4.success? + r0 = r4 + else + r5 = super + if r5.success? + r0 = r5 + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + end + end + end + end + + node_cache[:expression][start_index] = r0 + + return r0 + end + + module Definition0 + def space + elements[1] + end + + def variable + elements[2] + end + + def space + elements[3] + end + + def expression + elements[4] + end + end + + module Definition1 + def eval(env) + env[variable.name] = expression.eval(env) + end + end + + def _nt_definition + start_index = index + cached = node_cache[:definition][index] + if cached + @index = cached.interval.end + return cached + end + + i0, s0 = index, [] + r1 = parse_terminal('def', SyntaxNode) + s0 << r1 + if r1.success? + r2 = _nt_space + s0 << r2 + if r2.success? + r3 = _nt_variable + s0 << r3 + if r3.success? + r4 = _nt_space + s0 << r4 + if r4.success? + r5 = _nt_expression + s0 << r5 + end + end + end + end + if s0.last.success? + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(Definition0) + r0.extend(Definition1) + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + + node_cache[:definition][start_index] = r0 + + return r0 + end + + module Conditional0 + def space + elements[1] + end + + def space + elements[3] + end + + def condition + elements[4] + end + + def space + elements[5] + end + + def space + elements[7] + end + + def true_case + elements[8] + end + + def space + elements[9] + end + + def space + elements[11] + end + + def false_case + elements[12] + end + end + + module Conditional1 + def eval(env) + if condition.eval(env) + true_case.eval(env) + else + false_case.eval(env) + end + end + end + + def _nt_conditional + start_index = index + cached = node_cache[:conditional][index] + if cached + @index = cached.interval.end + return cached + end + + i0, s0 = index, [] + r1 = parse_terminal('if', SyntaxNode) + s0 << r1 + if r1.success? + r2 = _nt_space + s0 << r2 + if r2.success? + r3 = parse_terminal('(', SyntaxNode) + s0 << r3 + if r3.success? + r4 = _nt_space + s0 << r4 + if r4.success? + r5 = _nt_expression + s0 << r5 + if r5.success? + r6 = _nt_space + s0 << r6 + if r6.success? + r7 = parse_terminal(')', SyntaxNode) + s0 << r7 + if r7.success? + r8 = _nt_space + s0 << r8 + if r8.success? + r9 = _nt_expression + s0 << r9 + if r9.success? + r10 = _nt_space + s0 << r10 + if r10.success? + r11 = parse_terminal('else', SyntaxNode) + s0 << r11 + if r11.success? + r12 = _nt_space + s0 << r12 + if r12.success? + r13 = _nt_expression + s0 << r13 + end + end + end + end + end + end + end + end + end + end + end + end + if s0.last.success? + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(Conditional0) + r0.extend(Conditional1) + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + + node_cache[:conditional][start_index] = r0 + + return r0 + end + + def _nt_primary + start_index = index + cached = node_cache[:primary][index] + if cached + @index = cached.interval.end + return cached + end + + i0 = index + r1 = _nt_application + if r1.success? + r0 = r1 + else + r2 = super + if r2.success? + r0 = r2 + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + end + + node_cache[:primary][start_index] = r0 + + return r0 + end + + module Application0 + def operator + elements[0] + end + + def space + elements[1] + end + + def expression + elements[2] + end + end + + module Application1 + def eval(env={}) + left_associative_apply(operator.eval(env), env) + end + + def left_associative_apply(operator, env) + if expression.instance_of?(Application) + expression.left_associative_apply(operator.apply(expression.operator.eval(env)), env) + else + operator.apply(expression.eval(env)) + end + end + + def to_s(env={}) + operator.to_s(env) + ' ' + expression.to_s(env) + end + end + + def _nt_application + start_index = index + cached = node_cache[:application][index] + if cached + @index = cached.interval.end + return cached + end + + i0, s0 = index, [] + r1 = _nt_operator + s0 << r1 + if r1.success? + r2 = _nt_space + s0 << r2 + if r2.success? + r3 = _nt_expression + s0 << r3 + end + end + if s0.last.success? + r0 = (Application).new(input, i0...index, s0) + r0.extend(Application0) + r0.extend(Application1) + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + + node_cache[:application][start_index] = r0 + + return r0 + end + + def _nt_operator + start_index = index + cached = node_cache[:operator][index] + if cached + @index = cached.interval.end + return cached + end + + i0 = index + r1 = _nt_function + if r1.success? + r0 = r1 + else + r2 = _nt_variable + if r2.success? + r0 = r2 + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + end + + node_cache[:operator][start_index] = r0 + + return r0 + end + + def _nt_non_application + start_index = index + cached = node_cache[:non_application][index] + if cached + @index = cached.interval.end + return cached + end + + i0 = index + r1 = _nt_function + if r1.success? + r0 = r1 + else + r2 = _nt_variable + if r2.success? + r0 = r2 + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + end + + node_cache[:non_application][start_index] = r0 + + return r0 + end + + module Function0 + def param + elements[1] + end + + def body + elements[3] + end + + end + + module Function1 + class Closure + attr_reader :env, :function + + def initialize(function, env) + @function = function + @env = env + end + + def apply(arg) + function.body.eval(function.param.bind(arg, env)) + end + + def to_s(other_env={}) + "\\#{function.param.to_s}(#{function.body.to_s(other_env.merge(env))})" + end + end + + def eval(env={}) + Closure.new(self, env) + end + + def to_s(env={}) + eval(env).to_s + end + end + + def _nt_function + start_index = index + cached = node_cache[:function][index] + if cached + @index = cached.interval.end + return cached + end + + i0, s0 = index, [] + r1 = parse_terminal('\\', SyntaxNode) + s0 << r1 + if r1.success? + r2 = _nt_variable + s0 << r2 + if r2.success? + r3 = parse_terminal('(', SyntaxNode) + s0 << r3 + if r3.success? + r4 = _nt_expression + s0 << r4 + if r4.success? + r5 = parse_terminal(')', SyntaxNode) + s0 << r5 + end + end + end + end + if s0.last.success? + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(Function0) + r0.extend(Function1) + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + + node_cache[:function][start_index] = r0 + + return r0 + end + + module Variable0 + def bind(value, env) + env.merge(name => value) + end + + def to_s(env={}) + env.has_key?(name) ? env[name].to_s : name + end + end + + module Variable1 + end + + def _nt_variable + start_index = index + cached = node_cache[:variable][index] + if cached + @index = cached.interval.end + return cached + end + + i0, s0 = index, [] + i1 = index + r2 = _nt_keyword + if r2.success? + r1 = ParseFailure.new(input, i1) + else + self.index = i1 + r1 = SyntaxNode.new(input, index...index) + end + s0 << r1 + if r1.success? + r3 = super + r3.extend(Variable0) + s0 << r3 + end + if s0.last.success? + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(Variable1) + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + + node_cache[:variable][start_index] = r0 + + return r0 + end + + module Keyword0 + end + + def _nt_keyword + start_index = index + cached = node_cache[:keyword][index] + if cached + @index = cached.interval.end + return cached + end + + i0, s0 = index, [] + i1 = index + r2 = parse_terminal('if', SyntaxNode) + if r2.success? + r1 = r2 + else + r3 = parse_terminal('else', SyntaxNode) + if r3.success? + r1 = r3 + else + self.index = i1 + r1 = ParseFailure.new(input, i1) + end + end + s0 << r1 + if r1.success? + i4 = index + r5 = _nt_non_space_char + if r5.success? + r4 = ParseFailure.new(input, i4) + else + self.index = i4 + r4 = SyntaxNode.new(input, index...index) + end + s0 << r4 + end + if s0.last.success? + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(Keyword0) + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + + node_cache[:keyword][start_index] = r0 + + return r0 + end + + module NonSpaceChar0 + end + + def _nt_non_space_char + start_index = index + cached = node_cache[:non_space_char][index] + if cached + @index = cached.interval.end + return cached + end + + i0, s0 = index, [] + i1 = index + r2 = parse_char_class(/[ \n]/, ' \n', SyntaxNode) + if r2.success? + r1 = ParseFailure.new(input, i1) + else + self.index = i1 + r1 = SyntaxNode.new(input, index...index) + end + s0 << r1 + if r1.success? + r3 = parse_anything(SyntaxNode) + s0 << r3 + end + if s0.last.success? + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(NonSpaceChar0) + else + self.index = i0 + r0 = ParseFailure.new(input, i0) + end + + node_cache[:non_space_char][start_index] = r0 + + return r0 + end + + def _nt_space + start_index = index + cached = node_cache[:space][index] + if cached + @index = cached.interval.end + return cached + end + + s0, i0 = [], index + loop do + r1 = parse_char_class(/[ \n]/, ' \n', SyntaxNode) + if r1.success? + s0 << r1 + else + break + end + end + r0 = SyntaxNode.new(input, i0...index, s0) + + node_cache[:space][start_index] = r0 + + return r0 + end + +end + +class LambdaCalculusParser < Treetop::Runtime::CompiledParser + include LambdaCalculus +end diff --git a/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus.treetop b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus.treetop new file mode 100755 index 0000000..7e72c93 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus.treetop @@ -0,0 +1,132 @@ +grammar LambdaCalculus + include Arithmetic + + rule program + expression more_expressions:(';' space expression)* { + def eval(env={}) + env = env.clone + last_eval = nil + expressions.each do |exp| + last_eval = exp.eval(env) + end + last_eval + end + + def expressions + [expression] + more_expressions.elements.map {|elt| elt.expression} + end + } + end + + rule expression + definition / conditional / application / function / super + end + + rule definition + 'def' space variable space expression { + def eval(env) + env[variable.name] = expression.eval(env) + end + } + end + + rule conditional + 'if' space '(' space condition:expression space ')' space + true_case:expression space 'else' space false_case:expression { + def eval(env) + if condition.eval(env) + true_case.eval(env) + else + false_case.eval(env) + end + end + } + end + + rule primary + application / super + end + + rule application + operator space expression { + def eval(env={}) + left_associative_apply(operator.eval(env), env) + end + + def left_associative_apply(operator, env) + if expression.instance_of?(Application) + expression.left_associative_apply(operator.apply(expression.operator.eval(env)), env) + else + operator.apply(expression.eval(env)) + end + end + + def to_s(env={}) + operator.to_s(env) + ' ' + expression.to_s(env) + end + } + end + + rule operator + function / variable + end + + rule non_application + function / variable + end + + rule function + '\\' param:variable '(' body:expression ')' { + class Closure + attr_reader :env, :function + + def initialize(function, env) + @function = function + @env = env + end + + def apply(arg) + function.body.eval(function.param.bind(arg, env)) + end + + def to_s(other_env={}) + "\\#{function.param.to_s}(#{function.body.to_s(other_env.merge(env))})" + end + end + + def eval(env={}) + Closure.new(self, env) + end + + def to_s(env={}) + eval(env).to_s + end + } + end + + rule variable + !keyword ( + super { + def bind(value, env) + env.merge(name => value) + end + + def to_s(env={}) + env.has_key?(name) ? env[name].to_s : name + end + } + ) + end + + rule keyword + ('if' / 'else') !non_space_char + end + + rule non_space_char + ![ \n] . + end + + rule space + [ \n]* + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus_node_classes.rb b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus_node_classes.rb new file mode 100755 index 0000000..9a220ec --- /dev/null +++ b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus_node_classes.rb @@ -0,0 +1,5 @@ +module LambdaCalculus + class Application < Treetop::Runtime::SyntaxNode + + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus_test.rb b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus_test.rb new file mode 100755 index 0000000..0844ef0 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/lambda_calculus_test.rb @@ -0,0 +1,89 @@ +dir = File.dirname(__FILE__) +require File.expand_path("#{dir}/test_helper") +require File.expand_path("#{dir}/arithmetic_node_classes") +require File.expand_path("#{dir}/lambda_calculus_node_classes") +Treetop.load File.expand_path("#{dir}/arithmetic") +Treetop.load File.expand_path("#{dir}/lambda_calculus") + +class Treetop::Runtime::SyntaxNode + def method_missing(method, *args) + raise "Node representing #{text_value} does not respond to #{method}" + end +end + +class LambdaCalculusParserTest < Test::Unit::TestCase + include ParserTestHelper + + def setup + @parser = LambdaCalculusParser.new + end + + def test_free_variable + assert_equal 'x', parse('x').eval.to_s + end + + def test_variable_binding + variable = parse('x').eval + env = variable.bind(1, {}) + assert_equal 1, env['x'] + end + + def test_bound_variable_evaluation + assert_equal 1, parse('x').eval({'x' => 1}) + end + + def test_identity_function + assert_equal '\x(x)', parse('\x(x)').eval.to_s + end + + def test_function_returning_constant_function + assert_equal '\x(\y(x))', parse('\x(\y(x))').eval.to_s + end + + def test_identity_function_application + assert_equal 1, parse('\x(x) 1').eval + assert_equal '\y(y)', parse('\x(x) \y(y)').eval.to_s + end + + def test_constant_function_construction + assert_equal '\y(1)', parse('\x(\y(x)) 1').eval.to_s + end + + def test_multiple_argument_application_is_left_associative + assert_equal '\b(b)', parse('\x(\y(x y)) \a(a) \b(b)').eval.to_s + end + + def test_parentheses_override_application_order + assert_equal '\y(\b(b) y)', parse('\x(\y(x y)) (\a(a) \b(b))').eval.to_s + end + + def test_arithmetic_in_function_body + assert_equal 10, parse('\x(x + 5) 5').eval + end + + def test_addition_of_function_results + assert_equal 20, parse('\x(x + 5) 5 + \x(15 - x) 5').eval + end + + def test_conditional + result = parse('if (x) 1 else 2') + assert_equal 1, result.eval({'x' => true}) + assert_equal 2, result.eval({'x' => false}) + end + + def test_keyword + assert @parser.parse('if').failure? + assert @parser.parse('else').failure? + assert parse('elsee').success? + assert parse('iff').success? + end + + def test_program + result = parse('def fact \x(if (x == 0) + 1 + else + x * fact (x - 1)); + fact(5)').eval + assert_equal 5 * 4 * 3 * 2, result + end +end diff --git a/vendor/gems/treetop-1.2.5/examples/lambda_calculus/test_helper.rb b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/test_helper.rb new file mode 100755 index 0000000..bfdb7ad --- /dev/null +++ b/vendor/gems/treetop-1.2.5/examples/lambda_calculus/test_helper.rb @@ -0,0 +1,18 @@ +require 'test/unit' +require 'rubygems' +require 'treetop' + +module ParserTestHelper + def assert_evals_to_self(input) + assert_evals_to(input, input) + end + + def parse(input) + result = @parser.parse(input) + unless result + puts @parser.terminal_failures.join("\n") + end + assert !result.nil? + result + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop.rb b/vendor/gems/treetop-1.2.5/lib/treetop.rb new file mode 100755 index 0000000..ed00cbf --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop.rb @@ -0,0 +1,11 @@ +require 'rubygems' + +dir = File.dirname(__FILE__) + +TREETOP_ROOT = File.join(dir, 'treetop') +require File.join(TREETOP_ROOT, "ruby_extensions") +require File.join(TREETOP_ROOT, "runtime") +require File.join(TREETOP_ROOT, "compiler") + +require 'polyglot' +Polyglot.register(["treetop", "tt"], Treetop) diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/bootstrap_gen_1_metagrammar.rb b/vendor/gems/treetop-1.2.5/lib/treetop/bootstrap_gen_1_metagrammar.rb new file mode 100755 index 0000000..f587bfa --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/bootstrap_gen_1_metagrammar.rb @@ -0,0 +1,45 @@ +# This file's job is to load a Treetop::Compiler::Metagrammar and Treetop::Compiler::MetagrammarParser +# into the environment by compiling the current metagrammar.treetop using a trusted version of Treetop. + +require 'rubygems' +dir = File.dirname(__FILE__) + +TREETOP_VERSION_REQUIRED_TO_BOOTSTRAP = '>= 1.1.5' + +# Loading trusted version of Treetop to compile the compiler +gem_spec = Gem.source_index.find_name('treetop', TREETOP_VERSION_REQUIRED_TO_BOOTSTRAP).last +raise "Install a Treetop Gem version #{TREETOP_VERSION_REQUIRED_TO_BOOTSTRAP} to bootstrap." unless gem_spec +trusted_treetop_path = gem_spec.full_gem_path +require File.join(trusted_treetop_path, 'lib', 'treetop') + +# Relocating trusted version of Treetop to Trusted::Treetop +Trusted = Module.new +Trusted::Treetop = Treetop +Object.send(:remove_const, :Treetop) +Object.send(:remove_const, :TREETOP_ROOT) + +# Requiring version of Treetop that is under test +$exclude_metagrammar = true +require File.expand_path(File.join(dir, '..', 'treetop')) + +# Compile and evaluate freshly generated metagrammar source +METAGRAMMAR_PATH = File.join(TREETOP_ROOT, 'compiler', 'metagrammar.treetop') +compiled_metagrammar_source = Trusted::Treetop::Compiler::GrammarCompiler.new.ruby_source(METAGRAMMAR_PATH) +Object.class_eval(compiled_metagrammar_source) + +# The compiler under test was compiled with the trusted grammar and therefore depends on its runtime +# But the runtime in the global namespace is the new runtime. We therefore inject the trusted runtime +# into the compiler so its parser functions correctly. It will still not work for custom classes that +# explicitly subclass the wrong runtime. For now I am working around this by keeping 1 generation of +# backward compatibility in these cases. +# Treetop::Compiler::Metagrammar.module_eval do +# include Trusted::Treetop::Runtime +# end +# +# Treetop::Compiler.send(:remove_const, :MetagrammarParser) +# class Treetop::Compiler::MetagrammarParser < Trusted::Treetop::Runtime::CompiledParser +# include Treetop::Compiler::Metagrammar +# include Trusted::Treetop::Runtime +# end + +$bootstrapped_gen_1_metagrammar = true \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler.rb new file mode 100755 index 0000000..5ccc72d --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler.rb @@ -0,0 +1,6 @@ +dir = File.dirname(__FILE__) +require File.join(dir, *%w[compiler lexical_address_space]) +require File.join(dir, *%w[compiler ruby_builder]) +require File.join(dir, *%w[compiler node_classes]) +require File.join(dir, *%w[compiler metagrammar]) unless $exclude_metagrammar +require File.join(dir, *%w[compiler grammar_compiler]) diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/grammar_compiler.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/grammar_compiler.rb new file mode 100755 index 0000000..e3b233e --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/grammar_compiler.rb @@ -0,0 +1,40 @@ +module Treetop + module Compiler + class GrammarCompiler + def compile(source_path, target_path = source_path.gsub(/\.(treetop|tt)\Z/, '.rb')) + File.open(target_path, 'w') do |target_file| + target_file.write(ruby_source(source_path)) + end + end + + # compile a treetop file into ruby + def ruby_source(source_path) + ruby_source_from_string(File.read(source_path)) + end + + # compile a string containing treetop source into ruby + def ruby_source_from_string(s) + parser = MetagrammarParser.new + result = parser.parse(s) + unless result + raise RuntimeError.new(parser.failure_reason) + end + result.compile + end + end + end + + # compile a treetop source file and load it + def self.load(path) + adjusted_path = path =~ /\.(treetop|tt)\Z/ ? path : path + '.treetop' + File.open(adjusted_path) do |source_file| + load_from_string(source_file.read) + end + end + + # compile a treetop source string and load it + def self.load_from_string(s) + compiler = Treetop::Compiler::GrammarCompiler.new + Object.class_eval(compiler.ruby_source_from_string(s)) + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/lexical_address_space.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/lexical_address_space.rb new file mode 100755 index 0000000..a09478c --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/lexical_address_space.rb @@ -0,0 +1,17 @@ +module Treetop + module Compiler + class LexicalAddressSpace + def initialize + reset_addresses + end + + def next_address + @next_address += 1 + end + + def reset_addresses + @next_address = -1 + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/metagrammar.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/metagrammar.rb new file mode 100755 index 0000000..d1a41de --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/metagrammar.rb @@ -0,0 +1,2955 @@ +module Treetop + module Compiler + module Metagrammar + include Treetop::Runtime + + def root + @root || :treetop_file + end + + module TreetopFile0 + def prefix + elements[0] + end + + def module_or_grammar + elements[1] + end + + def suffix + elements[2] + end + end + + module TreetopFile1 + def compile + prefix.text_value + module_or_grammar.compile + suffix.text_value + end + end + + def _nt_treetop_file + start_index = index + if node_cache[:treetop_file].has_key?(index) + cached = node_cache[:treetop_file][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + r2 = _nt_space + if r2 + r1 = r2 + else + r1 = SyntaxNode.new(input, index...index) + end + s0 << r1 + if r1 + i3 = index + r4 = _nt_module_declaration + if r4 + r3 = r4 + else + r5 = _nt_grammar + if r5 + r3 = r5 + else + self.index = i3 + r3 = nil + end + end + s0 << r3 + if r3 + r7 = _nt_space + if r7 + r6 = r7 + else + r6 = SyntaxNode.new(input, index...index) + end + s0 << r6 + end + end + if s0.last + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(TreetopFile0) + r0.extend(TreetopFile1) + else + self.index = i0 + r0 = nil + end + + node_cache[:treetop_file][start_index] = r0 + + return r0 + end + + module ModuleDeclaration0 + def space + elements[1] + end + + def space + elements[4] + end + end + + module ModuleDeclaration1 + def space + elements[0] + end + + end + + module ModuleDeclaration2 + def prefix + elements[0] + end + + def module_contents + elements[1] + end + + def suffix + elements[2] + end + end + + module ModuleDeclaration3 + def compile + prefix.text_value + module_contents.compile + suffix.text_value + end + end + + def _nt_module_declaration + start_index = index + if node_cache[:module_declaration].has_key?(index) + cached = node_cache[:module_declaration][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + i1, s1 = index, [] + if input.index('module', index) == index + r2 = (SyntaxNode).new(input, index...(index + 6)) + @index += 6 + else + terminal_parse_failure('module') + r2 = nil + end + s1 << r2 + if r2 + r3 = _nt_space + s1 << r3 + if r3 + if input.index(Regexp.new('[A-Z]'), index) == index + r4 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + r4 = nil + end + s1 << r4 + if r4 + s5, i5 = [], index + loop do + r6 = _nt_alphanumeric_char + if r6 + s5 << r6 + else + break + end + end + r5 = SyntaxNode.new(input, i5...index, s5) + s1 << r5 + if r5 + r7 = _nt_space + s1 << r7 + end + end + end + end + if s1.last + r1 = (SyntaxNode).new(input, i1...index, s1) + r1.extend(ModuleDeclaration0) + else + self.index = i1 + r1 = nil + end + s0 << r1 + if r1 + i8 = index + r9 = _nt_module_declaration + if r9 + r8 = r9 + else + r10 = _nt_grammar + if r10 + r8 = r10 + else + self.index = i8 + r8 = nil + end + end + s0 << r8 + if r8 + i11, s11 = index, [] + r12 = _nt_space + s11 << r12 + if r12 + if input.index('end', index) == index + r13 = (SyntaxNode).new(input, index...(index + 3)) + @index += 3 + else + terminal_parse_failure('end') + r13 = nil + end + s11 << r13 + end + if s11.last + r11 = (SyntaxNode).new(input, i11...index, s11) + r11.extend(ModuleDeclaration1) + else + self.index = i11 + r11 = nil + end + s0 << r11 + end + end + if s0.last + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(ModuleDeclaration2) + r0.extend(ModuleDeclaration3) + else + self.index = i0 + r0 = nil + end + + node_cache[:module_declaration][start_index] = r0 + + return r0 + end + + module Grammar0 + def space + elements[1] + end + end + + module Grammar1 + def space + elements[1] + end + + def grammar_name + elements[2] + end + + def space + elements[3] + end + + def declaration_sequence + elements[5] + end + + end + + def _nt_grammar + start_index = index + if node_cache[:grammar].has_key?(index) + cached = node_cache[:grammar][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('grammar', index) == index + r1 = (SyntaxNode).new(input, index...(index + 7)) + @index += 7 + else + terminal_parse_failure('grammar') + r1 = nil + end + s0 << r1 + if r1 + r2 = _nt_space + s0 << r2 + if r2 + r3 = _nt_grammar_name + s0 << r3 + if r3 + r4 = _nt_space + s0 << r4 + if r4 + i6, s6 = index, [] + if input.index('do', index) == index + r7 = (SyntaxNode).new(input, index...(index + 2)) + @index += 2 + else + terminal_parse_failure('do') + r7 = nil + end + s6 << r7 + if r7 + r8 = _nt_space + s6 << r8 + end + if s6.last + r6 = (SyntaxNode).new(input, i6...index, s6) + r6.extend(Grammar0) + else + self.index = i6 + r6 = nil + end + if r6 + r5 = r6 + else + r5 = SyntaxNode.new(input, index...index) + end + s0 << r5 + if r5 + r9 = _nt_declaration_sequence + s0 << r9 + if r9 + r11 = _nt_space + if r11 + r10 = r11 + else + r10 = SyntaxNode.new(input, index...index) + end + s0 << r10 + if r10 + if input.index('end', index) == index + r12 = (SyntaxNode).new(input, index...(index + 3)) + @index += 3 + else + terminal_parse_failure('end') + r12 = nil + end + s0 << r12 + end + end + end + end + end + end + end + if s0.last + r0 = (Grammar).new(input, i0...index, s0) + r0.extend(Grammar1) + else + self.index = i0 + r0 = nil + end + + node_cache[:grammar][start_index] = r0 + + return r0 + end + + module GrammarName0 + end + + def _nt_grammar_name + start_index = index + if node_cache[:grammar_name].has_key?(index) + cached = node_cache[:grammar_name][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index(Regexp.new('[A-Z]'), index) == index + r1 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + r1 = nil + end + s0 << r1 + if r1 + s2, i2 = [], index + loop do + r3 = _nt_alphanumeric_char + if r3 + s2 << r3 + else + break + end + end + r2 = SyntaxNode.new(input, i2...index, s2) + s0 << r2 + end + if s0.last + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(GrammarName0) + else + self.index = i0 + r0 = nil + end + + node_cache[:grammar_name][start_index] = r0 + + return r0 + end + + module DeclarationSequence0 + def space + elements[0] + end + + def declaration + elements[1] + end + end + + module DeclarationSequence1 + def head + elements[0] + end + + def tail + elements[1] + end + end + + module DeclarationSequence2 + def declarations + [head] + tail + end + + def tail + super.elements.map { |elt| elt.declaration } + end + end + + module DeclarationSequence3 + def compile(builder) + end + end + + def _nt_declaration_sequence + start_index = index + if node_cache[:declaration_sequence].has_key?(index) + cached = node_cache[:declaration_sequence][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + i1, s1 = index, [] + r2 = _nt_declaration + s1 << r2 + if r2 + s3, i3 = [], index + loop do + i4, s4 = index, [] + r5 = _nt_space + s4 << r5 + if r5 + r6 = _nt_declaration + s4 << r6 + end + if s4.last + r4 = (SyntaxNode).new(input, i4...index, s4) + r4.extend(DeclarationSequence0) + else + self.index = i4 + r4 = nil + end + if r4 + s3 << r4 + else + break + end + end + r3 = SyntaxNode.new(input, i3...index, s3) + s1 << r3 + end + if s1.last + r1 = (DeclarationSequence).new(input, i1...index, s1) + r1.extend(DeclarationSequence1) + r1.extend(DeclarationSequence2) + else + self.index = i1 + r1 = nil + end + if r1 + r0 = r1 + else + if input.index('', index) == index + r7 = (SyntaxNode).new(input, index...(index + 0)) + r7.extend(DeclarationSequence3) + @index += 0 + else + terminal_parse_failure('') + r7 = nil + end + if r7 + r0 = r7 + else + self.index = i0 + r0 = nil + end + end + + node_cache[:declaration_sequence][start_index] = r0 + + return r0 + end + + def _nt_declaration + start_index = index + if node_cache[:declaration].has_key?(index) + cached = node_cache[:declaration][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + r1 = _nt_parsing_rule + if r1 + r0 = r1 + else + r2 = _nt_include_declaration + if r2 + r0 = r2 + else + self.index = i0 + r0 = nil + end + end + + node_cache[:declaration][start_index] = r0 + + return r0 + end + + module IncludeDeclaration0 + def space + elements[1] + end + + end + + module IncludeDeclaration1 + def compile(builder) + builder << text_value + end + end + + def _nt_include_declaration + start_index = index + if node_cache[:include_declaration].has_key?(index) + cached = node_cache[:include_declaration][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('include', index) == index + r1 = (SyntaxNode).new(input, index...(index + 7)) + @index += 7 + else + terminal_parse_failure('include') + r1 = nil + end + s0 << r1 + if r1 + r2 = _nt_space + s0 << r2 + if r2 + if input.index(Regexp.new('[A-Z]'), index) == index + r3 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + r3 = nil + end + s0 << r3 + if r3 + s4, i4 = [], index + loop do + i5 = index + r6 = _nt_alphanumeric_char + if r6 + r5 = r6 + else + if input.index('::', index) == index + r7 = (SyntaxNode).new(input, index...(index + 2)) + @index += 2 + else + terminal_parse_failure('::') + r7 = nil + end + if r7 + r5 = r7 + else + self.index = i5 + r5 = nil + end + end + if r5 + s4 << r5 + else + break + end + end + r4 = SyntaxNode.new(input, i4...index, s4) + s0 << r4 + end + end + end + if s0.last + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(IncludeDeclaration0) + r0.extend(IncludeDeclaration1) + else + self.index = i0 + r0 = nil + end + + node_cache[:include_declaration][start_index] = r0 + + return r0 + end + + module ParsingRule0 + def space + elements[1] + end + end + + module ParsingRule1 + def space + elements[1] + end + + def nonterminal + elements[2] + end + + def space + elements[3] + end + + def parsing_expression + elements[5] + end + + def space + elements[6] + end + + end + + def _nt_parsing_rule + start_index = index + if node_cache[:parsing_rule].has_key?(index) + cached = node_cache[:parsing_rule][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('rule', index) == index + r1 = (SyntaxNode).new(input, index...(index + 4)) + @index += 4 + else + terminal_parse_failure('rule') + r1 = nil + end + s0 << r1 + if r1 + r2 = _nt_space + s0 << r2 + if r2 + r3 = _nt_nonterminal + s0 << r3 + if r3 + r4 = _nt_space + s0 << r4 + if r4 + i6, s6 = index, [] + if input.index('do', index) == index + r7 = (SyntaxNode).new(input, index...(index + 2)) + @index += 2 + else + terminal_parse_failure('do') + r7 = nil + end + s6 << r7 + if r7 + r8 = _nt_space + s6 << r8 + end + if s6.last + r6 = (SyntaxNode).new(input, i6...index, s6) + r6.extend(ParsingRule0) + else + self.index = i6 + r6 = nil + end + if r6 + r5 = r6 + else + r5 = SyntaxNode.new(input, index...index) + end + s0 << r5 + if r5 + r9 = _nt_parsing_expression + s0 << r9 + if r9 + r10 = _nt_space + s0 << r10 + if r10 + if input.index('end', index) == index + r11 = (SyntaxNode).new(input, index...(index + 3)) + @index += 3 + else + terminal_parse_failure('end') + r11 = nil + end + s0 << r11 + end + end + end + end + end + end + end + if s0.last + r0 = (ParsingRule).new(input, i0...index, s0) + r0.extend(ParsingRule1) + else + self.index = i0 + r0 = nil + end + + node_cache[:parsing_rule][start_index] = r0 + + return r0 + end + + def _nt_parsing_expression + start_index = index + if node_cache[:parsing_expression].has_key?(index) + cached = node_cache[:parsing_expression][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + r1 = _nt_choice + if r1 + r0 = r1 + else + r2 = _nt_sequence + if r2 + r0 = r2 + else + r3 = _nt_primary + if r3 + r0 = r3 + else + self.index = i0 + r0 = nil + end + end + end + + node_cache[:parsing_expression][start_index] = r0 + + return r0 + end + + module Choice0 + def alternative + elements[3] + end + end + + module Choice1 + def head + elements[0] + end + + def tail + elements[1] + end + end + + module Choice2 + def alternatives + [head] + tail + end + + def tail + super.elements.map {|elt| elt.alternative} + end + + def inline_modules + (alternatives.map {|alt| alt.inline_modules }).flatten + end + end + + def _nt_choice + start_index = index + if node_cache[:choice].has_key?(index) + cached = node_cache[:choice][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + r1 = _nt_alternative + s0 << r1 + if r1 + s2, i2 = [], index + loop do + i3, s3 = index, [] + r5 = _nt_space + if r5 + r4 = r5 + else + r4 = SyntaxNode.new(input, index...index) + end + s3 << r4 + if r4 + if input.index('/', index) == index + r6 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('/') + r6 = nil + end + s3 << r6 + if r6 + r8 = _nt_space + if r8 + r7 = r8 + else + r7 = SyntaxNode.new(input, index...index) + end + s3 << r7 + if r7 + r9 = _nt_alternative + s3 << r9 + end + end + end + if s3.last + r3 = (SyntaxNode).new(input, i3...index, s3) + r3.extend(Choice0) + else + self.index = i3 + r3 = nil + end + if r3 + s2 << r3 + else + break + end + end + if s2.empty? + self.index = i2 + r2 = nil + else + r2 = SyntaxNode.new(input, i2...index, s2) + end + s0 << r2 + end + if s0.last + r0 = (Choice).new(input, i0...index, s0) + r0.extend(Choice1) + r0.extend(Choice2) + else + self.index = i0 + r0 = nil + end + + node_cache[:choice][start_index] = r0 + + return r0 + end + + module Sequence0 + def space + elements[0] + end + + def labeled_sequence_primary + elements[1] + end + end + + module Sequence1 + def head + elements[0] + end + + def tail + elements[1] + end + + def node_class_declarations + elements[2] + end + end + + module Sequence2 + def sequence_elements + [head] + tail + end + + def tail + super.elements.map {|elt| elt.labeled_sequence_primary } + end + + def inline_modules + (sequence_elements.map {|elt| elt.inline_modules}).flatten + + [sequence_element_accessor_module] + + node_class_declarations.inline_modules + end + + def inline_module_name + node_class_declarations.inline_module_name + end + end + + def _nt_sequence + start_index = index + if node_cache[:sequence].has_key?(index) + cached = node_cache[:sequence][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + r1 = _nt_labeled_sequence_primary + s0 << r1 + if r1 + s2, i2 = [], index + loop do + i3, s3 = index, [] + r4 = _nt_space + s3 << r4 + if r4 + r5 = _nt_labeled_sequence_primary + s3 << r5 + end + if s3.last + r3 = (SyntaxNode).new(input, i3...index, s3) + r3.extend(Sequence0) + else + self.index = i3 + r3 = nil + end + if r3 + s2 << r3 + else + break + end + end + if s2.empty? + self.index = i2 + r2 = nil + else + r2 = SyntaxNode.new(input, i2...index, s2) + end + s0 << r2 + if r2 + r6 = _nt_node_class_declarations + s0 << r6 + end + end + if s0.last + r0 = (Sequence).new(input, i0...index, s0) + r0.extend(Sequence1) + r0.extend(Sequence2) + else + self.index = i0 + r0 = nil + end + + node_cache[:sequence][start_index] = r0 + + return r0 + end + + def _nt_alternative + start_index = index + if node_cache[:alternative].has_key?(index) + cached = node_cache[:alternative][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + r1 = _nt_sequence + if r1 + r0 = r1 + else + r2 = _nt_primary + if r2 + r0 = r2 + else + self.index = i0 + r0 = nil + end + end + + node_cache[:alternative][start_index] = r0 + + return r0 + end + + module Primary0 + def prefix + elements[0] + end + + def atomic + elements[1] + end + end + + module Primary1 + def compile(address, builder, parent_expression=nil) + prefix.compile(address, builder, self) + end + + def prefixed_expression + atomic + end + + def inline_modules + atomic.inline_modules + end + + def inline_module_name + nil + end + end + + module Primary2 + def atomic + elements[0] + end + + def suffix + elements[1] + end + + def node_class_declarations + elements[2] + end + end + + module Primary3 + def compile(address, builder, parent_expression=nil) + suffix.compile(address, builder, self) + end + + def optional_expression + atomic + end + + def node_class_name + node_class_declarations.node_class_name + end + + def inline_modules + atomic.inline_modules + node_class_declarations.inline_modules + end + + def inline_module_name + node_class_declarations.inline_module_name + end + end + + module Primary4 + def atomic + elements[0] + end + + def node_class_declarations + elements[1] + end + end + + module Primary5 + def compile(address, builder, parent_expression=nil) + atomic.compile(address, builder, self) + end + + def node_class_name + node_class_declarations.node_class_name + end + + def inline_modules + atomic.inline_modules + node_class_declarations.inline_modules + end + + def inline_module_name + node_class_declarations.inline_module_name + end + end + + def _nt_primary + start_index = index + if node_cache[:primary].has_key?(index) + cached = node_cache[:primary][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + i1, s1 = index, [] + r2 = _nt_prefix + s1 << r2 + if r2 + r3 = _nt_atomic + s1 << r3 + end + if s1.last + r1 = (SyntaxNode).new(input, i1...index, s1) + r1.extend(Primary0) + r1.extend(Primary1) + else + self.index = i1 + r1 = nil + end + if r1 + r0 = r1 + else + i4, s4 = index, [] + r5 = _nt_atomic + s4 << r5 + if r5 + r6 = _nt_suffix + s4 << r6 + if r6 + r7 = _nt_node_class_declarations + s4 << r7 + end + end + if s4.last + r4 = (SyntaxNode).new(input, i4...index, s4) + r4.extend(Primary2) + r4.extend(Primary3) + else + self.index = i4 + r4 = nil + end + if r4 + r0 = r4 + else + i8, s8 = index, [] + r9 = _nt_atomic + s8 << r9 + if r9 + r10 = _nt_node_class_declarations + s8 << r10 + end + if s8.last + r8 = (SyntaxNode).new(input, i8...index, s8) + r8.extend(Primary4) + r8.extend(Primary5) + else + self.index = i8 + r8 = nil + end + if r8 + r0 = r8 + else + self.index = i0 + r0 = nil + end + end + end + + node_cache[:primary][start_index] = r0 + + return r0 + end + + module LabeledSequencePrimary0 + def label + elements[0] + end + + def sequence_primary + elements[1] + end + end + + module LabeledSequencePrimary1 + def compile(lexical_address, builder) + sequence_primary.compile(lexical_address, builder) + end + + def inline_modules + sequence_primary.inline_modules + end + + def label_name + if label.name + label.name + elsif sequence_primary.instance_of?(Nonterminal) + sequence_primary.text_value + else + nil + end + end + end + + def _nt_labeled_sequence_primary + start_index = index + if node_cache[:labeled_sequence_primary].has_key?(index) + cached = node_cache[:labeled_sequence_primary][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + r1 = _nt_label + s0 << r1 + if r1 + r2 = _nt_sequence_primary + s0 << r2 + end + if s0.last + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(LabeledSequencePrimary0) + r0.extend(LabeledSequencePrimary1) + else + self.index = i0 + r0 = nil + end + + node_cache[:labeled_sequence_primary][start_index] = r0 + + return r0 + end + + module Label0 + def alpha_char + elements[0] + end + + end + + module Label1 + end + + module Label2 + def name + elements[0].text_value + end + end + + module Label3 + def name + nil + end + end + + def _nt_label + start_index = index + if node_cache[:label].has_key?(index) + cached = node_cache[:label][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + i1, s1 = index, [] + i2, s2 = index, [] + r3 = _nt_alpha_char + s2 << r3 + if r3 + s4, i4 = [], index + loop do + r5 = _nt_alphanumeric_char + if r5 + s4 << r5 + else + break + end + end + r4 = SyntaxNode.new(input, i4...index, s4) + s2 << r4 + end + if s2.last + r2 = (SyntaxNode).new(input, i2...index, s2) + r2.extend(Label0) + else + self.index = i2 + r2 = nil + end + s1 << r2 + if r2 + if input.index(':', index) == index + r6 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure(':') + r6 = nil + end + s1 << r6 + end + if s1.last + r1 = (SyntaxNode).new(input, i1...index, s1) + r1.extend(Label1) + r1.extend(Label2) + else + self.index = i1 + r1 = nil + end + if r1 + r0 = r1 + else + if input.index('', index) == index + r7 = (SyntaxNode).new(input, index...(index + 0)) + r7.extend(Label3) + @index += 0 + else + terminal_parse_failure('') + r7 = nil + end + if r7 + r0 = r7 + else + self.index = i0 + r0 = nil + end + end + + node_cache[:label][start_index] = r0 + + return r0 + end + + module SequencePrimary0 + def prefix + elements[0] + end + + def atomic + elements[1] + end + end + + module SequencePrimary1 + def compile(lexical_address, builder) + prefix.compile(lexical_address, builder, self) + end + + def prefixed_expression + elements[1] + end + + def inline_modules + atomic.inline_modules + end + + def inline_module_name + nil + end + end + + module SequencePrimary2 + def atomic + elements[0] + end + + def suffix + elements[1] + end + end + + module SequencePrimary3 + def compile(lexical_address, builder) + suffix.compile(lexical_address, builder, self) + end + + def node_class_name + nil + end + + def inline_modules + atomic.inline_modules + end + + def inline_module_name + nil + end + end + + def _nt_sequence_primary + start_index = index + if node_cache[:sequence_primary].has_key?(index) + cached = node_cache[:sequence_primary][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + i1, s1 = index, [] + r2 = _nt_prefix + s1 << r2 + if r2 + r3 = _nt_atomic + s1 << r3 + end + if s1.last + r1 = (SyntaxNode).new(input, i1...index, s1) + r1.extend(SequencePrimary0) + r1.extend(SequencePrimary1) + else + self.index = i1 + r1 = nil + end + if r1 + r0 = r1 + else + i4, s4 = index, [] + r5 = _nt_atomic + s4 << r5 + if r5 + r6 = _nt_suffix + s4 << r6 + end + if s4.last + r4 = (SyntaxNode).new(input, i4...index, s4) + r4.extend(SequencePrimary2) + r4.extend(SequencePrimary3) + else + self.index = i4 + r4 = nil + end + if r4 + r0 = r4 + else + r7 = _nt_atomic + if r7 + r0 = r7 + else + self.index = i0 + r0 = nil + end + end + end + + node_cache[:sequence_primary][start_index] = r0 + + return r0 + end + + def _nt_suffix + start_index = index + if node_cache[:suffix].has_key?(index) + cached = node_cache[:suffix][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + r1 = _nt_repetition_suffix + if r1 + r0 = r1 + else + r2 = _nt_optional_suffix + if r2 + r0 = r2 + else + self.index = i0 + r0 = nil + end + end + + node_cache[:suffix][start_index] = r0 + + return r0 + end + + def _nt_optional_suffix + start_index = index + if node_cache[:optional_suffix].has_key?(index) + cached = node_cache[:optional_suffix][index] + @index = cached.interval.end if cached + return cached + end + + if input.index('?', index) == index + r0 = (Optional).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('?') + r0 = nil + end + + node_cache[:optional_suffix][start_index] = r0 + + return r0 + end + + module NodeClassDeclarations0 + def node_class_expression + elements[0] + end + + def trailing_inline_module + elements[1] + end + end + + module NodeClassDeclarations1 + def node_class_name + node_class_expression.node_class_name + end + + def inline_modules + trailing_inline_module.inline_modules + end + + def inline_module + trailing_inline_module.inline_module + end + + def inline_module_name + inline_module.module_name if inline_module + end + end + + def _nt_node_class_declarations + start_index = index + if node_cache[:node_class_declarations].has_key?(index) + cached = node_cache[:node_class_declarations][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + r1 = _nt_node_class_expression + s0 << r1 + if r1 + r2 = _nt_trailing_inline_module + s0 << r2 + end + if s0.last + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(NodeClassDeclarations0) + r0.extend(NodeClassDeclarations1) + else + self.index = i0 + r0 = nil + end + + node_cache[:node_class_declarations][start_index] = r0 + + return r0 + end + + def _nt_repetition_suffix + start_index = index + if node_cache[:repetition_suffix].has_key?(index) + cached = node_cache[:repetition_suffix][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + if input.index('+', index) == index + r1 = (OneOrMore).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('+') + r1 = nil + end + if r1 + r0 = r1 + else + if input.index('*', index) == index + r2 = (ZeroOrMore).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('*') + r2 = nil + end + if r2 + r0 = r2 + else + self.index = i0 + r0 = nil + end + end + + node_cache[:repetition_suffix][start_index] = r0 + + return r0 + end + + def _nt_prefix + start_index = index + if node_cache[:prefix].has_key?(index) + cached = node_cache[:prefix][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + if input.index('&', index) == index + r1 = (AndPredicate).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('&') + r1 = nil + end + if r1 + r0 = r1 + else + if input.index('!', index) == index + r2 = (NotPredicate).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('!') + r2 = nil + end + if r2 + r0 = r2 + else + if input.index('~', index) == index + r3 = (TransientPrefix).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('~') + r3 = nil + end + if r3 + r0 = r3 + else + self.index = i0 + r0 = nil + end + end + end + + node_cache[:prefix][start_index] = r0 + + return r0 + end + + def _nt_atomic + start_index = index + if node_cache[:atomic].has_key?(index) + cached = node_cache[:atomic][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + r1 = _nt_terminal + if r1 + r0 = r1 + else + r2 = _nt_nonterminal + if r2 + r0 = r2 + else + r3 = _nt_parenthesized_expression + if r3 + r0 = r3 + else + self.index = i0 + r0 = nil + end + end + end + + node_cache[:atomic][start_index] = r0 + + return r0 + end + + module ParenthesizedExpression0 + def parsing_expression + elements[2] + end + + end + + module ParenthesizedExpression1 + def inline_modules + parsing_expression.inline_modules + end + end + + def _nt_parenthesized_expression + start_index = index + if node_cache[:parenthesized_expression].has_key?(index) + cached = node_cache[:parenthesized_expression][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('(', index) == index + r1 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('(') + r1 = nil + end + s0 << r1 + if r1 + r3 = _nt_space + if r3 + r2 = r3 + else + r2 = SyntaxNode.new(input, index...index) + end + s0 << r2 + if r2 + r4 = _nt_parsing_expression + s0 << r4 + if r4 + r6 = _nt_space + if r6 + r5 = r6 + else + r5 = SyntaxNode.new(input, index...index) + end + s0 << r5 + if r5 + if input.index(')', index) == index + r7 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure(')') + r7 = nil + end + s0 << r7 + end + end + end + end + if s0.last + r0 = (ParenthesizedExpression).new(input, i0...index, s0) + r0.extend(ParenthesizedExpression0) + r0.extend(ParenthesizedExpression1) + else + self.index = i0 + r0 = nil + end + + node_cache[:parenthesized_expression][start_index] = r0 + + return r0 + end + + module Nonterminal0 + def alpha_char + elements[0] + end + + end + + module Nonterminal1 + end + + def _nt_nonterminal + start_index = index + if node_cache[:nonterminal].has_key?(index) + cached = node_cache[:nonterminal][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + i1 = index + r2 = _nt_keyword_inside_grammar + if r2 + r1 = nil + else + self.index = i1 + r1 = SyntaxNode.new(input, index...index) + end + s0 << r1 + if r1 + i3, s3 = index, [] + r4 = _nt_alpha_char + s3 << r4 + if r4 + s5, i5 = [], index + loop do + r6 = _nt_alphanumeric_char + if r6 + s5 << r6 + else + break + end + end + r5 = SyntaxNode.new(input, i5...index, s5) + s3 << r5 + end + if s3.last + r3 = (SyntaxNode).new(input, i3...index, s3) + r3.extend(Nonterminal0) + else + self.index = i3 + r3 = nil + end + s0 << r3 + end + if s0.last + r0 = (Nonterminal).new(input, i0...index, s0) + r0.extend(Nonterminal1) + else + self.index = i0 + r0 = nil + end + + node_cache[:nonterminal][start_index] = r0 + + return r0 + end + + def _nt_terminal + start_index = index + if node_cache[:terminal].has_key?(index) + cached = node_cache[:terminal][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + r1 = _nt_quoted_string + if r1 + r0 = r1 + else + r2 = _nt_character_class + if r2 + r0 = r2 + else + r3 = _nt_anything_symbol + if r3 + r0 = r3 + else + self.index = i0 + r0 = nil + end + end + end + + node_cache[:terminal][start_index] = r0 + + return r0 + end + + module QuotedString0 + def string + super.text_value + end + end + + def _nt_quoted_string + start_index = index + if node_cache[:quoted_string].has_key?(index) + cached = node_cache[:quoted_string][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + r1 = _nt_single_quoted_string + if r1 + r0 = r1 + r0.extend(QuotedString0) + else + r2 = _nt_double_quoted_string + if r2 + r0 = r2 + r0.extend(QuotedString0) + else + self.index = i0 + r0 = nil + end + end + + node_cache[:quoted_string][start_index] = r0 + + return r0 + end + + module DoubleQuotedString0 + end + + module DoubleQuotedString1 + def string + elements[1] + end + + end + + def _nt_double_quoted_string + start_index = index + if node_cache[:double_quoted_string].has_key?(index) + cached = node_cache[:double_quoted_string][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('"', index) == index + r1 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('"') + r1 = nil + end + s0 << r1 + if r1 + s2, i2 = [], index + loop do + i3, s3 = index, [] + i4 = index + if input.index('"', index) == index + r5 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('"') + r5 = nil + end + if r5 + r4 = nil + else + self.index = i4 + r4 = SyntaxNode.new(input, index...index) + end + s3 << r4 + if r4 + i6 = index + if input.index("\\\\", index) == index + r7 = (SyntaxNode).new(input, index...(index + 2)) + @index += 2 + else + terminal_parse_failure("\\\\") + r7 = nil + end + if r7 + r6 = r7 + else + if input.index('\"', index) == index + r8 = (SyntaxNode).new(input, index...(index + 2)) + @index += 2 + else + terminal_parse_failure('\"') + r8 = nil + end + if r8 + r6 = r8 + else + if index < input_length + r9 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure("any character") + r9 = nil + end + if r9 + r6 = r9 + else + self.index = i6 + r6 = nil + end + end + end + s3 << r6 + end + if s3.last + r3 = (SyntaxNode).new(input, i3...index, s3) + r3.extend(DoubleQuotedString0) + else + self.index = i3 + r3 = nil + end + if r3 + s2 << r3 + else + break + end + end + r2 = SyntaxNode.new(input, i2...index, s2) + s0 << r2 + if r2 + if input.index('"', index) == index + r10 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('"') + r10 = nil + end + s0 << r10 + end + end + if s0.last + r0 = (Terminal).new(input, i0...index, s0) + r0.extend(DoubleQuotedString1) + else + self.index = i0 + r0 = nil + end + + node_cache[:double_quoted_string][start_index] = r0 + + return r0 + end + + module SingleQuotedString0 + end + + module SingleQuotedString1 + def string + elements[1] + end + + end + + def _nt_single_quoted_string + start_index = index + if node_cache[:single_quoted_string].has_key?(index) + cached = node_cache[:single_quoted_string][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index("'", index) == index + r1 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure("'") + r1 = nil + end + s0 << r1 + if r1 + s2, i2 = [], index + loop do + i3, s3 = index, [] + i4 = index + if input.index("'", index) == index + r5 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure("'") + r5 = nil + end + if r5 + r4 = nil + else + self.index = i4 + r4 = SyntaxNode.new(input, index...index) + end + s3 << r4 + if r4 + i6 = index + if input.index("\\\\", index) == index + r7 = (SyntaxNode).new(input, index...(index + 2)) + @index += 2 + else + terminal_parse_failure("\\\\") + r7 = nil + end + if r7 + r6 = r7 + else + if input.index("\\'", index) == index + r8 = (SyntaxNode).new(input, index...(index + 2)) + @index += 2 + else + terminal_parse_failure("\\'") + r8 = nil + end + if r8 + r6 = r8 + else + if index < input_length + r9 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure("any character") + r9 = nil + end + if r9 + r6 = r9 + else + self.index = i6 + r6 = nil + end + end + end + s3 << r6 + end + if s3.last + r3 = (SyntaxNode).new(input, i3...index, s3) + r3.extend(SingleQuotedString0) + else + self.index = i3 + r3 = nil + end + if r3 + s2 << r3 + else + break + end + end + r2 = SyntaxNode.new(input, i2...index, s2) + s0 << r2 + if r2 + if input.index("'", index) == index + r10 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure("'") + r10 = nil + end + s0 << r10 + end + end + if s0.last + r0 = (Terminal).new(input, i0...index, s0) + r0.extend(SingleQuotedString1) + else + self.index = i0 + r0 = nil + end + + node_cache[:single_quoted_string][start_index] = r0 + + return r0 + end + + module CharacterClass0 + end + + module CharacterClass1 + end + + module CharacterClass2 + end + + module CharacterClass3 + def characters + elements[1] + end + + end + + module CharacterClass4 + def characters + super.text_value + end + end + + def _nt_character_class + start_index = index + if node_cache[:character_class].has_key?(index) + cached = node_cache[:character_class][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('[', index) == index + r1 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('[') + r1 = nil + end + s0 << r1 + if r1 + s2, i2 = [], index + loop do + i3, s3 = index, [] + i4 = index + if input.index(']', index) == index + r5 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure(']') + r5 = nil + end + if r5 + r4 = nil + else + self.index = i4 + r4 = SyntaxNode.new(input, index...index) + end + s3 << r4 + if r4 + i6 = index + i7, s7 = index, [] + if input.index('\\', index) == index + r8 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('\\') + r8 = nil + end + s7 << r8 + if r8 + if index < input_length + r9 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure("any character") + r9 = nil + end + s7 << r9 + end + if s7.last + r7 = (SyntaxNode).new(input, i7...index, s7) + r7.extend(CharacterClass0) + else + self.index = i7 + r7 = nil + end + if r7 + r6 = r7 + else + i10, s10 = index, [] + i11 = index + if input.index('\\', index) == index + r12 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('\\') + r12 = nil + end + if r12 + r11 = nil + else + self.index = i11 + r11 = SyntaxNode.new(input, index...index) + end + s10 << r11 + if r11 + if index < input_length + r13 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure("any character") + r13 = nil + end + s10 << r13 + end + if s10.last + r10 = (SyntaxNode).new(input, i10...index, s10) + r10.extend(CharacterClass1) + else + self.index = i10 + r10 = nil + end + if r10 + r6 = r10 + else + self.index = i6 + r6 = nil + end + end + s3 << r6 + end + if s3.last + r3 = (SyntaxNode).new(input, i3...index, s3) + r3.extend(CharacterClass2) + else + self.index = i3 + r3 = nil + end + if r3 + s2 << r3 + else + break + end + end + if s2.empty? + self.index = i2 + r2 = nil + else + r2 = SyntaxNode.new(input, i2...index, s2) + end + s0 << r2 + if r2 + if input.index(']', index) == index + r14 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure(']') + r14 = nil + end + s0 << r14 + end + end + if s0.last + r0 = (CharacterClass).new(input, i0...index, s0) + r0.extend(CharacterClass3) + r0.extend(CharacterClass4) + else + self.index = i0 + r0 = nil + end + + node_cache[:character_class][start_index] = r0 + + return r0 + end + + def _nt_anything_symbol + start_index = index + if node_cache[:anything_symbol].has_key?(index) + cached = node_cache[:anything_symbol][index] + @index = cached.interval.end if cached + return cached + end + + if input.index('.', index) == index + r0 = (AnythingSymbol).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('.') + r0 = nil + end + + node_cache[:anything_symbol][start_index] = r0 + + return r0 + end + + module NodeClassExpression0 + end + + module NodeClassExpression1 + def space + elements[0] + end + + end + + module NodeClassExpression2 + def node_class_name + elements[2].text_value + end + end + + module NodeClassExpression3 + def node_class_name + nil + end + end + + def _nt_node_class_expression + start_index = index + if node_cache[:node_class_expression].has_key?(index) + cached = node_cache[:node_class_expression][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + i1, s1 = index, [] + r2 = _nt_space + s1 << r2 + if r2 + if input.index('<', index) == index + r3 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('<') + r3 = nil + end + s1 << r3 + if r3 + s4, i4 = [], index + loop do + i5, s5 = index, [] + i6 = index + if input.index('>', index) == index + r7 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('>') + r7 = nil + end + if r7 + r6 = nil + else + self.index = i6 + r6 = SyntaxNode.new(input, index...index) + end + s5 << r6 + if r6 + if index < input_length + r8 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure("any character") + r8 = nil + end + s5 << r8 + end + if s5.last + r5 = (SyntaxNode).new(input, i5...index, s5) + r5.extend(NodeClassExpression0) + else + self.index = i5 + r5 = nil + end + if r5 + s4 << r5 + else + break + end + end + if s4.empty? + self.index = i4 + r4 = nil + else + r4 = SyntaxNode.new(input, i4...index, s4) + end + s1 << r4 + if r4 + if input.index('>', index) == index + r9 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('>') + r9 = nil + end + s1 << r9 + end + end + end + if s1.last + r1 = (SyntaxNode).new(input, i1...index, s1) + r1.extend(NodeClassExpression1) + r1.extend(NodeClassExpression2) + else + self.index = i1 + r1 = nil + end + if r1 + r0 = r1 + else + if input.index('', index) == index + r10 = (SyntaxNode).new(input, index...(index + 0)) + r10.extend(NodeClassExpression3) + @index += 0 + else + terminal_parse_failure('') + r10 = nil + end + if r10 + r0 = r10 + else + self.index = i0 + r0 = nil + end + end + + node_cache[:node_class_expression][start_index] = r0 + + return r0 + end + + module TrailingInlineModule0 + def space + elements[0] + end + + def inline_module + elements[1] + end + end + + module TrailingInlineModule1 + def inline_modules + [inline_module] + end + + def inline_module_name + inline_module.module_name + end + end + + module TrailingInlineModule2 + def inline_modules + [] + end + + def inline_module + nil + end + + def inline_module_name + nil + end + end + + def _nt_trailing_inline_module + start_index = index + if node_cache[:trailing_inline_module].has_key?(index) + cached = node_cache[:trailing_inline_module][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + i1, s1 = index, [] + r2 = _nt_space + s1 << r2 + if r2 + r3 = _nt_inline_module + s1 << r3 + end + if s1.last + r1 = (SyntaxNode).new(input, i1...index, s1) + r1.extend(TrailingInlineModule0) + r1.extend(TrailingInlineModule1) + else + self.index = i1 + r1 = nil + end + if r1 + r0 = r1 + else + if input.index('', index) == index + r4 = (SyntaxNode).new(input, index...(index + 0)) + r4.extend(TrailingInlineModule2) + @index += 0 + else + terminal_parse_failure('') + r4 = nil + end + if r4 + r0 = r4 + else + self.index = i0 + r0 = nil + end + end + + node_cache[:trailing_inline_module][start_index] = r0 + + return r0 + end + + module InlineModule0 + end + + module InlineModule1 + end + + def _nt_inline_module + start_index = index + if node_cache[:inline_module].has_key?(index) + cached = node_cache[:inline_module][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('{', index) == index + r1 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('{') + r1 = nil + end + s0 << r1 + if r1 + s2, i2 = [], index + loop do + i3 = index + r4 = _nt_inline_module + if r4 + r3 = r4 + else + i5, s5 = index, [] + i6 = index + if input.index(Regexp.new('[{}]'), index) == index + r7 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + r7 = nil + end + if r7 + r6 = nil + else + self.index = i6 + r6 = SyntaxNode.new(input, index...index) + end + s5 << r6 + if r6 + if index < input_length + r8 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure("any character") + r8 = nil + end + s5 << r8 + end + if s5.last + r5 = (SyntaxNode).new(input, i5...index, s5) + r5.extend(InlineModule0) + else + self.index = i5 + r5 = nil + end + if r5 + r3 = r5 + else + self.index = i3 + r3 = nil + end + end + if r3 + s2 << r3 + else + break + end + end + r2 = SyntaxNode.new(input, i2...index, s2) + s0 << r2 + if r2 + if input.index('}', index) == index + r9 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('}') + r9 = nil + end + s0 << r9 + end + end + if s0.last + r0 = (InlineModule).new(input, i0...index, s0) + r0.extend(InlineModule1) + else + self.index = i0 + r0 = nil + end + + node_cache[:inline_module][start_index] = r0 + + return r0 + end + + module KeywordInsideGrammar0 + end + + def _nt_keyword_inside_grammar + start_index = index + if node_cache[:keyword_inside_grammar].has_key?(index) + cached = node_cache[:keyword_inside_grammar][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + i1 = index + if input.index('rule', index) == index + r2 = (SyntaxNode).new(input, index...(index + 4)) + @index += 4 + else + terminal_parse_failure('rule') + r2 = nil + end + if r2 + r1 = r2 + else + if input.index('end', index) == index + r3 = (SyntaxNode).new(input, index...(index + 3)) + @index += 3 + else + terminal_parse_failure('end') + r3 = nil + end + if r3 + r1 = r3 + else + self.index = i1 + r1 = nil + end + end + s0 << r1 + if r1 + i4 = index + r5 = _nt_non_space_char + if r5 + r4 = nil + else + self.index = i4 + r4 = SyntaxNode.new(input, index...index) + end + s0 << r4 + end + if s0.last + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(KeywordInsideGrammar0) + else + self.index = i0 + r0 = nil + end + + node_cache[:keyword_inside_grammar][start_index] = r0 + + return r0 + end + + module NonSpaceChar0 + end + + def _nt_non_space_char + start_index = index + if node_cache[:non_space_char].has_key?(index) + cached = node_cache[:non_space_char][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + i1 = index + r2 = _nt_space + if r2 + r1 = nil + else + self.index = i1 + r1 = SyntaxNode.new(input, index...index) + end + s0 << r1 + if r1 + if index < input_length + r3 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure("any character") + r3 = nil + end + s0 << r3 + end + if s0.last + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(NonSpaceChar0) + else + self.index = i0 + r0 = nil + end + + node_cache[:non_space_char][start_index] = r0 + + return r0 + end + + def _nt_alpha_char + start_index = index + if node_cache[:alpha_char].has_key?(index) + cached = node_cache[:alpha_char][index] + @index = cached.interval.end if cached + return cached + end + + if input.index(Regexp.new('[A-Za-z_]'), index) == index + r0 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + r0 = nil + end + + node_cache[:alpha_char][start_index] = r0 + + return r0 + end + + def _nt_alphanumeric_char + start_index = index + if node_cache[:alphanumeric_char].has_key?(index) + cached = node_cache[:alphanumeric_char][index] + @index = cached.interval.end if cached + return cached + end + + i0 = index + r1 = _nt_alpha_char + if r1 + r0 = r1 + else + if input.index(Regexp.new('[0-9]'), index) == index + r2 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + r2 = nil + end + if r2 + r0 = r2 + else + self.index = i0 + r0 = nil + end + end + + node_cache[:alphanumeric_char][start_index] = r0 + + return r0 + end + + def _nt_space + start_index = index + if node_cache[:space].has_key?(index) + cached = node_cache[:space][index] + @index = cached.interval.end if cached + return cached + end + + s0, i0 = [], index + loop do + i1 = index + r2 = _nt_white + if r2 + r1 = r2 + else + r3 = _nt_comment_to_eol + if r3 + r1 = r3 + else + self.index = i1 + r1 = nil + end + end + if r1 + s0 << r1 + else + break + end + end + if s0.empty? + self.index = i0 + r0 = nil + else + r0 = SyntaxNode.new(input, i0...index, s0) + end + + node_cache[:space][start_index] = r0 + + return r0 + end + + module CommentToEol0 + end + + module CommentToEol1 + end + + def _nt_comment_to_eol + start_index = index + if node_cache[:comment_to_eol].has_key?(index) + cached = node_cache[:comment_to_eol][index] + @index = cached.interval.end if cached + return cached + end + + i0, s0 = index, [] + if input.index('#', index) == index + r1 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure('#') + r1 = nil + end + s0 << r1 + if r1 + s2, i2 = [], index + loop do + i3, s3 = index, [] + i4 = index + if input.index("\n", index) == index + r5 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure("\n") + r5 = nil + end + if r5 + r4 = nil + else + self.index = i4 + r4 = SyntaxNode.new(input, index...index) + end + s3 << r4 + if r4 + if index < input_length + r6 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + terminal_parse_failure("any character") + r6 = nil + end + s3 << r6 + end + if s3.last + r3 = (SyntaxNode).new(input, i3...index, s3) + r3.extend(CommentToEol0) + else + self.index = i3 + r3 = nil + end + if r3 + s2 << r3 + else + break + end + end + r2 = SyntaxNode.new(input, i2...index, s2) + s0 << r2 + end + if s0.last + r0 = (SyntaxNode).new(input, i0...index, s0) + r0.extend(CommentToEol1) + else + self.index = i0 + r0 = nil + end + + node_cache[:comment_to_eol][start_index] = r0 + + return r0 + end + + def _nt_white + start_index = index + if node_cache[:white].has_key?(index) + cached = node_cache[:white][index] + @index = cached.interval.end if cached + return cached + end + + if input.index(Regexp.new('[ \\t\\n\\r]'), index) == index + r0 = (SyntaxNode).new(input, index...(index + 1)) + @index += 1 + else + r0 = nil + end + + node_cache[:white][start_index] = r0 + + return r0 + end + + end + + class MetagrammarParser < Treetop::Runtime::CompiledParser + include Metagrammar + end + + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/metagrammar.treetop b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/metagrammar.treetop new file mode 100755 index 0000000..354bac1 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/metagrammar.treetop @@ -0,0 +1,404 @@ +module Treetop + module Compiler + grammar Metagrammar + rule treetop_file + prefix:space? module_or_grammar:(module_declaration / grammar) suffix:space? { + def compile + prefix.text_value + module_or_grammar.compile + suffix.text_value + end + } + end + + rule module_declaration + prefix:('module' space [A-Z] alphanumeric_char* space) module_contents:(module_declaration / grammar) suffix:(space 'end') { + def compile + prefix.text_value + module_contents.compile + suffix.text_value + end + } + end + + rule grammar + 'grammar' space grammar_name space ('do' space)? declaration_sequence space? 'end' + end + + rule grammar_name + ([A-Z] alphanumeric_char*) + end + + rule declaration_sequence + head:declaration tail:(space declaration)* { + def declarations + [head] + tail + end + + def tail + super.elements.map { |elt| elt.declaration } + end + } + / + '' { + def compile(builder) + end + } + end + + rule declaration + parsing_rule / include_declaration + end + + rule include_declaration + 'include' space [A-Z] (alphanumeric_char / '::')* { + def compile(builder) + builder << text_value + end + } + end + + rule parsing_rule + 'rule' space nonterminal space ('do' space)? parsing_expression space 'end' + end + + rule parsing_expression + choice / sequence / primary + end + + rule choice + head:alternative tail:(space? '/' space? alternative)+ { + def alternatives + [head] + tail + end + + def tail + super.elements.map {|elt| elt.alternative} + end + + def inline_modules + (alternatives.map {|alt| alt.inline_modules }).flatten + end + } + end + + rule sequence + head:labeled_sequence_primary tail:(space labeled_sequence_primary)+ node_class_declarations { + def sequence_elements + [head] + tail + end + + def tail + super.elements.map {|elt| elt.labeled_sequence_primary } + end + + def inline_modules + (sequence_elements.map {|elt| elt.inline_modules}).flatten + + [sequence_element_accessor_module] + + node_class_declarations.inline_modules + end + + def inline_module_name + node_class_declarations.inline_module_name + end + } + end + + rule alternative + sequence / primary + end + + rule primary + prefix atomic { + def compile(address, builder, parent_expression=nil) + prefix.compile(address, builder, self) + end + + def prefixed_expression + atomic + end + + def inline_modules + atomic.inline_modules + end + + def inline_module_name + nil + end + } + / + atomic suffix node_class_declarations { + def compile(address, builder, parent_expression=nil) + suffix.compile(address, builder, self) + end + + def optional_expression + atomic + end + + def node_class_name + node_class_declarations.node_class_name + end + + def inline_modules + atomic.inline_modules + node_class_declarations.inline_modules + end + + def inline_module_name + node_class_declarations.inline_module_name + end + } + / + atomic node_class_declarations { + def compile(address, builder, parent_expression=nil) + atomic.compile(address, builder, self) + end + + def node_class_name + node_class_declarations.node_class_name + end + + def inline_modules + atomic.inline_modules + node_class_declarations.inline_modules + end + + def inline_module_name + node_class_declarations.inline_module_name + end + } + end + + rule labeled_sequence_primary + label sequence_primary { + def compile(lexical_address, builder) + sequence_primary.compile(lexical_address, builder) + end + + def inline_modules + sequence_primary.inline_modules + end + + def label_name + if label.name + label.name + elsif sequence_primary.instance_of?(Nonterminal) + sequence_primary.text_value + else + nil + end + end + } + end + + rule label + (alpha_char alphanumeric_char*) ':' { + def name + elements[0].text_value + end + } + / + '' { + def name + nil + end + } + end + + rule sequence_primary + prefix atomic { + def compile(lexical_address, builder) + prefix.compile(lexical_address, builder, self) + end + + def prefixed_expression + elements[1] + end + + def inline_modules + atomic.inline_modules + end + + def inline_module_name + nil + end + } + / + atomic suffix { + def compile(lexical_address, builder) + suffix.compile(lexical_address, builder, self) + end + + def node_class_name + nil + end + + def inline_modules + atomic.inline_modules + end + + def inline_module_name + nil + end + } + / + atomic + end + + rule suffix + repetition_suffix / optional_suffix + end + + rule optional_suffix + '?' + end + + rule node_class_declarations + node_class_expression trailing_inline_module { + def node_class_name + node_class_expression.node_class_name + end + + def inline_modules + trailing_inline_module.inline_modules + end + + def inline_module + trailing_inline_module.inline_module + end + + def inline_module_name + inline_module.module_name if inline_module + end + } + end + + rule repetition_suffix + '+' / '*' + end + + rule prefix + '&' / '!' / '~' + end + + rule atomic + terminal + / + nonterminal + / + parenthesized_expression + end + + rule parenthesized_expression + '(' space? parsing_expression space? ')' { + def inline_modules + parsing_expression.inline_modules + end + } + end + + rule nonterminal + !keyword_inside_grammar (alpha_char alphanumeric_char*) + end + + rule terminal + quoted_string / character_class / anything_symbol + end + + rule quoted_string + (single_quoted_string / double_quoted_string) { + def string + super.text_value + end + } + end + + rule double_quoted_string + '"' string:(!'"' ("\\\\" / '\"' / .))* '"' + end + + rule single_quoted_string + "'" string:(!"'" ("\\\\" / "\\'" / .))* "'" + end + + rule character_class + '[' characters:(!']' ('\\' . /!'\\' .))+ ']' { + def characters + super.text_value + end + } + end + + rule anything_symbol + '.' + end + + rule node_class_expression + space '<' (!'>' .)+ '>' { + def node_class_name + elements[2].text_value + end + } + / + '' { + def node_class_name + nil + end + } + end + + rule trailing_inline_module + space inline_module { + def inline_modules + [inline_module] + end + + def inline_module_name + inline_module.module_name + end + } + / + '' { + def inline_modules + [] + end + + def inline_module + nil + end + + def inline_module_name + nil + end + } + end + + rule inline_module + '{' (inline_module / ![{}] .)* '}' + end + + rule keyword_inside_grammar + ('rule' / 'end') !non_space_char + end + + rule non_space_char + !space . + end + + rule alpha_char + [A-Za-z_] + end + + rule alphanumeric_char + alpha_char / [0-9] + end + + rule space + (white / comment_to_eol)+ + end + + rule comment_to_eol + '#' (!"\n" .)* + end + + rule white + [ \t\n\r] + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes.rb new file mode 100755 index 0000000..a15793c --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes.rb @@ -0,0 +1,19 @@ +dir = File.dirname(__FILE__) +require File.join(dir, *%w[node_classes parsing_expression]) +require File.join(dir, *%w[node_classes atomic_expression]) +require File.join(dir, *%w[node_classes inline_module]) +require File.join(dir, *%w[node_classes treetop_file]) +require File.join(dir, *%w[node_classes grammar]) +require File.join(dir, *%w[node_classes declaration_sequence]) +require File.join(dir, *%w[node_classes parsing_rule]) +require File.join(dir, *%w[node_classes parenthesized_expression]) +require File.join(dir, *%w[node_classes nonterminal]) +require File.join(dir, *%w[node_classes terminal]) +require File.join(dir, *%w[node_classes anything_symbol]) +require File.join(dir, *%w[node_classes character_class]) +require File.join(dir, *%w[node_classes sequence]) +require File.join(dir, *%w[node_classes choice]) +require File.join(dir, *%w[node_classes repetition]) +require File.join(dir, *%w[node_classes optional]) +require File.join(dir, *%w[node_classes predicate]) +require File.join(dir, *%w[node_classes transient_prefix]) diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/anything_symbol.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/anything_symbol.rb new file mode 100755 index 0000000..4f2c26c --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/anything_symbol.rb @@ -0,0 +1,18 @@ +module Treetop + module Compiler + class AnythingSymbol < AtomicExpression + def compile(address, builder, parent_expression = nil) + super + builder.if__ "index < input_length" do + assign_result "instantiate_node(#{node_class_name},input, index...(index + 1))" + extend_result_with_inline_module + builder << "@index += 1" + end + builder.else_ do + builder << 'terminal_parse_failure("any character")' + assign_result 'nil' + end + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/atomic_expression.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/atomic_expression.rb new file mode 100755 index 0000000..7da74dd --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/atomic_expression.rb @@ -0,0 +1,14 @@ +module Treetop + module Compiler + class AtomicExpression < ParsingExpression + def inline_modules + [] + end + + def single_quote(string) + # Double any backslashes, then backslash any single-quotes: + "'#{string.gsub(/\\/) { '\\\\' }.gsub(/'/) { "\\'"}}'" + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/character_class.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/character_class.rb new file mode 100755 index 0000000..334d8c6 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/character_class.rb @@ -0,0 +1,19 @@ +module Treetop + module Compiler + class CharacterClass < AtomicExpression + def compile(address, builder, parent_expression = nil) + super + + builder.if__ "input.index(Regexp.new(#{single_quote(text_value)}), index) == index" do + assign_result "instantiate_node(#{node_class_name},input, index...(index + 1))" + extend_result_with_inline_module + builder << "@index += 1" + end + builder.else_ do + "terminal_parse_failure(#{single_quote(characters)})" + assign_result 'nil' + end + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/choice.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/choice.rb new file mode 100755 index 0000000..bd269a2 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/choice.rb @@ -0,0 +1,31 @@ +module Treetop + module Compiler + class Choice < ParsingExpression + def compile(address, builder, parent_expression = nil) + super + begin_comment(self) + use_vars :result, :start_index + compile_alternatives(alternatives) + end_comment(self) + end + + def compile_alternatives(alternatives) + obtain_new_subexpression_address + alternatives.first.compile(subexpression_address, builder) + builder.if__ subexpression_success? do + assign_result subexpression_result_var + extend_result_with_declared_module + extend_result_with_inline_module + end + builder.else_ do + if alternatives.size == 1 + reset_index + assign_failure start_index_var + else + compile_alternatives(alternatives[1..-1]) + end + end + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/declaration_sequence.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/declaration_sequence.rb new file mode 100755 index 0000000..a561d72 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/declaration_sequence.rb @@ -0,0 +1,24 @@ +module Treetop + module Compiler + class DeclarationSequence < Runtime::SyntaxNode + + def compile(builder) + unless rules.empty? + builder.method_declaration("root") do + builder << "@root || :#{rules.first.name}" + end + builder.newline + end + + declarations.each do |declaration| + declaration.compile(builder) + builder.newline + end + end + + def rules + declarations.select { |declaration| declaration.instance_of?(ParsingRule) } + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/grammar.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/grammar.rb new file mode 100755 index 0000000..41a205b --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/grammar.rb @@ -0,0 +1,28 @@ +module Treetop + module Compiler + class Grammar < Runtime::SyntaxNode + def compile + builder = RubyBuilder.new + + builder.module_declaration "#{grammar_name.text_value}" do + builder.in(indent_level) # account for initial indentation of grammar declaration + builder << "include Treetop::Runtime" + builder.newline + declaration_sequence.compile(builder) + end + builder.newline + builder.class_declaration "#{parser_name} < Treetop::Runtime::CompiledParser" do + builder << "include #{grammar_name.text_value}" + end + end + + def indent_level + input.column_of(interval.begin) - 1 + end + + def parser_name + grammar_name.text_value + 'Parser' + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/inline_module.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/inline_module.rb new file mode 100755 index 0000000..3cb1ef0 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/inline_module.rb @@ -0,0 +1,27 @@ +module Treetop + module Compiler + module InlineModuleMixin + attr_reader :module_name + + def compile(index, builder, rule) + @module_name = "#{rule.name.treetop_camelize}#{index}" + end + end + + class InlineModule < Runtime::SyntaxNode + + include InlineModuleMixin + + def compile(index, builder, rule) + super + builder.module_declaration(module_name) do + builder << ruby_code.gsub(/\A\n/, '').rstrip + end + end + + def ruby_code + elements[1].text_value + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/nonterminal.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/nonterminal.rb new file mode 100755 index 0000000..7421dbe --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/nonterminal.rb @@ -0,0 +1,13 @@ +module Treetop + module Compiler + class Nonterminal < AtomicExpression + def compile(address, builder, parent_expression = nil) + super + use_vars :result + assign_result text_value == 'super' ? 'super' : "_nt_#{text_value}" + extend_result_with_declared_module + extend_result_with_inline_module + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/optional.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/optional.rb new file mode 100755 index 0000000..72d2bb9 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/optional.rb @@ -0,0 +1,19 @@ +module Treetop + module Compiler + class Optional < ParsingExpression + def compile(address, builder, parent_expression) + super + use_vars :result + obtain_new_subexpression_address + parent_expression.atomic.compile(subexpression_address, builder) + + builder.if__ subexpression_success? do + assign_result subexpression_result_var + end + builder.else_ do + assign_result epsilon_node + end + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/parenthesized_expression.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/parenthesized_expression.rb new file mode 100755 index 0000000..e58f8f9 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/parenthesized_expression.rb @@ -0,0 +1,9 @@ +module Treetop + module Compiler + class ParenthesizedExpression < ParsingExpression + def compile(address, builder, parent_expression = nil) + elements[2].compile(address, builder, parent_expression) + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/parsing_expression.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/parsing_expression.rb new file mode 100755 index 0000000..2ad71e8 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/parsing_expression.rb @@ -0,0 +1,138 @@ +module Treetop + module Compiler + class ParsingExpression < Runtime::SyntaxNode + attr_reader :address, :builder, :subexpression_address, :var_symbols, :parent_expression + + def compile(address, builder, parent_expression) + @address = address + @builder = builder + @parent_expression = parent_expression + end + + def node_class_name + parent_expression && parent_expression.node_class_name || 'SyntaxNode' + end + + def declared_module_name + parent_expression && parent_expression.node_class_name + end + + def inline_module_name + parent_expression && parent_expression.inline_module_name + end + + def optional_arg(arg) + if arg + ", #{arg}" + else + '' + end + end + + def use_vars(*var_symbols) + @var_symbols = var_symbols + builder << var_initialization + end + + def result_var + var(:result) + end + + def accumulator_var + var(:accumulator) + end + + def start_index_var + var(:start_index) + end + + def subexpression_result_var + "r#{subexpression_address}" + end + + def subexpression_success? + subexpression_result_var + end + + def obtain_new_subexpression_address + @subexpression_address = builder.next_address + end + + def accumulate_subexpression_result + builder.accumulate accumulator_var, subexpression_result_var + end + + def assign_result(value_ruby) + builder.assign result_var, value_ruby + end + + def extend_result(module_name) + builder.extend result_var, module_name + end + + def extend_result_with_declared_module + extend_result declared_module_name if declared_module_name + end + + def extend_result_with_inline_module + extend_result inline_module_name if inline_module_name + end + + def reset_index + builder.assign 'self.index', start_index_var + end + + def epsilon_node + "instantiate_node(SyntaxNode,input, index...index)" + end + + def assign_failure(start_index_var) + assign_result("nil") + end + + def var_initialization + left, right = [], [] + var_symbols.each do |symbol| + if init_value(symbol) + left << var(symbol) + right << init_value(symbol) + end + end + if left.empty? + "" + else + left.join(', ') + ' = ' + right.join(', ') + end + end + + def var(var_symbol) + case var_symbol + when :result then "r#{address}" + when :accumulator then "s#{address}" + when :start_index then "i#{address}" + else raise "Unknown var symbol #{var_symbol}." + end + end + + def init_value(var_symbol) + case var_symbol + when :accumulator then '[]' + when :start_index then 'index' + else nil + end + end + + def begin_comment(expression) + #builder << "# begin #{on_one_line(expression)}" + end + + def end_comment(expression) + #builder << "# end #{on_one_line(expression)}" + end + + def on_one_line(expression) + expression.text_value.tr("\n", ' ') + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/parsing_rule.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/parsing_rule.rb new file mode 100755 index 0000000..723d52e --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/parsing_rule.rb @@ -0,0 +1,55 @@ +module Treetop + module Compiler + class ParsingRule < Runtime::SyntaxNode + + def compile(builder) + compile_inline_module_declarations(builder) + generate_method_definition(builder) + end + + def compile_inline_module_declarations(builder) + parsing_expression.inline_modules.each_with_index do |inline_module, i| + inline_module.compile(i, builder, self) + builder.newline + end + end + + def generate_method_definition(builder) + builder.reset_addresses + expression_address = builder.next_address + result_var = "r#{expression_address}" + + builder.method_declaration(method_name) do + builder.assign 'start_index', 'index' + generate_cache_lookup(builder) + builder.newline + parsing_expression.compile(expression_address, builder) + builder.newline + generate_cache_storage(builder, result_var) + builder.newline + builder << "return #{result_var}" + end + end + + def generate_cache_lookup(builder) + builder.if_ "node_cache[:#{name}].has_key?(index)" do + builder.assign 'cached', "node_cache[:#{name}][index]" + builder << '@index = cached.interval.end if cached' + builder << 'return cached' + end + end + + def generate_cache_storage(builder, result_var) + builder.assign "node_cache[:#{name}][start_index]", result_var + end + + def method_name + "_nt_#{name}" + end + + def name + nonterminal.text_value + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/predicate.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/predicate.rb new file mode 100755 index 0000000..f80d06e --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/predicate.rb @@ -0,0 +1,45 @@ +module Treetop + module Compiler + class Predicate < ParsingExpression + def compile(address, builder, parent_expression) + super + begin_comment(parent_expression) + use_vars :result, :start_index + obtain_new_subexpression_address + parent_expression.prefixed_expression.compile(subexpression_address, builder) + builder.if__(subexpression_success?) { when_success } + builder.else_ { when_failure } + end_comment(parent_expression) + end + + def assign_failure + super(start_index_var) + end + + def assign_success + reset_index + assign_result epsilon_node + end + end + + class AndPredicate < Predicate + def when_success + assign_success + end + + def when_failure + assign_failure + end + end + + class NotPredicate < Predicate + def when_success + assign_failure + end + + def when_failure + assign_success + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/repetition.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/repetition.rb new file mode 100755 index 0000000..2d7adc2 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/repetition.rb @@ -0,0 +1,55 @@ +module Treetop + module Compiler + class Repetition < ParsingExpression + def compile(address, builder, parent_expression) + super + repeated_expression = parent_expression.atomic + begin_comment(parent_expression) + use_vars :result, :accumulator, :start_index + + builder.loop do + obtain_new_subexpression_address + repeated_expression.compile(subexpression_address, builder) + builder.if__ subexpression_success? do + accumulate_subexpression_result + end + builder.else_ do + builder.break + end + end + end + + def inline_module_name + parent_expression.inline_module_name + end + + def assign_and_extend_result + assign_result "instantiate_node(#{node_class_name},input, #{start_index_var}...index, #{accumulator_var})" + extend_result_with_inline_module + end + end + + + class ZeroOrMore < Repetition + def compile(address, builder, parent_expression) + super + assign_and_extend_result + end_comment(parent_expression) + end + end + + class OneOrMore < Repetition + def compile(address, builder, parent_expression) + super + builder.if__ "#{accumulator_var}.empty?" do + reset_index + assign_failure start_index_var + end + builder.else_ do + assign_and_extend_result + end + end_comment(parent_expression) + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/sequence.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/sequence.rb new file mode 100755 index 0000000..ca2a906 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/sequence.rb @@ -0,0 +1,68 @@ +module Treetop + module Compiler + class Sequence < ParsingExpression + def compile(address, builder, parent_expression = nil) + super + begin_comment(self) + use_vars :result, :start_index, :accumulator + compile_sequence_elements(sequence_elements) + builder.if__ "#{accumulator_var}.last" do + assign_result "instantiate_node(#{node_class_name},input, #{start_index_var}...index, #{accumulator_var})" + extend_result sequence_element_accessor_module_name if sequence_element_accessor_module_name + extend_result_with_inline_module + end + builder.else_ do + reset_index + assign_failure start_index_var + end + end_comment(self) + end + + def node_class_name + node_class_declarations.node_class_name || 'SyntaxNode' + end + + def compile_sequence_elements(elements) + obtain_new_subexpression_address + elements.first.compile(subexpression_address, builder) + accumulate_subexpression_result + if elements.size > 1 + builder.if_ subexpression_success? do + compile_sequence_elements(elements[1..-1]) + end + end + end + + def sequence_element_accessor_module + @sequence_element_accessor_module ||= SequenceElementAccessorModule.new(sequence_elements) + end + + def sequence_element_accessor_module_name + sequence_element_accessor_module.module_name + end + end + + class SequenceElementAccessorModule + include InlineModuleMixin + attr_reader :sequence_elements + + def initialize(sequence_elements) + @sequence_elements = sequence_elements + end + + def compile(index, builder, rule) + super + builder.module_declaration(module_name) do + sequence_elements.each_with_index do |element, index| + if element.label_name + builder.method_declaration(element.label_name) do + builder << "elements[#{index}]" + end + builder.newline unless index == sequence_elements.size - 1 + end + end + end + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/terminal.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/terminal.rb new file mode 100755 index 0000000..51b94b4 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/terminal.rb @@ -0,0 +1,20 @@ +module Treetop + module Compiler + class Terminal < AtomicExpression + def compile(address, builder, parent_expression = nil) + super + string_length = eval(text_value).length + + builder.if__ "input.index(#{text_value}, index) == index" do + assign_result "instantiate_node(#{node_class_name},input, index...(index + #{string_length}))" + extend_result_with_inline_module + builder << "@index += #{string_length}" + end + builder.else_ do + builder << "terminal_parse_failure(#{text_value})" + assign_result 'nil' + end + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/transient_prefix.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/transient_prefix.rb new file mode 100755 index 0000000..4bd2498 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/transient_prefix.rb @@ -0,0 +1,9 @@ +module Treetop + module Compiler + class TransientPrefix < ParsingExpression + def compile(address, builder, parent_expression) + parent_expression.prefixed_expression.compile(address, builder) + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/treetop_file.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/treetop_file.rb new file mode 100755 index 0000000..ada9750 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/node_classes/treetop_file.rb @@ -0,0 +1,9 @@ +module Treetop + module Compiler + class TreetopFile < Runtime::SyntaxNode + def compile + (elements.map {|elt| elt.compile}).join + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/compiler/ruby_builder.rb b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/ruby_builder.rb new file mode 100755 index 0000000..bf4e05e --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/compiler/ruby_builder.rb @@ -0,0 +1,113 @@ +module Treetop + module Compiler + class RubyBuilder + + attr_reader :level, :address_space, :ruby + + def initialize + @level = 0 + @address_space = LexicalAddressSpace.new + @ruby = "" + end + + def <<(ruby_line) + return if ruby_line.blank? + ruby << ruby_line.tabto(level) << "\n" + end + + def newline + ruby << "\n" + end + + def indented(depth = 2) + self.in(depth) + yield + self.out(depth) + end + + def class_declaration(name, &block) + self << "class #{name}" + indented(&block) + self << "end" + end + + def module_declaration(name, &block) + self << "module #{name}" + indented(&block) + self << "end" + end + + def method_declaration(name, &block) + self << "def #{name}" + indented(&block) + self << "end" + end + + def assign(left, right) + if left.instance_of? Array + self << "#{left.join(', ')} = #{right.join(', ')}" + else + self << "#{left} = #{right}" + end + end + + def extend(var, module_name) + self << "#{var}.extend(#{module_name})" + end + + def accumulate(left, right) + self << "#{left} << #{right}" + end + + def if__(condition, &block) + self << "if #{condition}" + indented(&block) + end + + def if_(condition, &block) + if__(condition, &block) + self << 'end' + end + + def else_(&block) + self << 'else' + indented(&block) + self << 'end' + end + + def loop(&block) + self << 'loop do' + indented(&block) + self << 'end' + end + + def break + self << 'break' + end + + def in(depth = 2) + @level += depth + self + end + + def out(depth = 2) + @level -= depth + self + end + + def next_address + address_space.next_address + end + + def reset_addresses + address_space.reset_addresses + end + + protected + + def indent + " " * level + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/ruby_extensions.rb b/vendor/gems/treetop-1.2.5/lib/treetop/ruby_extensions.rb new file mode 100755 index 0000000..c271c7f --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/ruby_extensions.rb @@ -0,0 +1,2 @@ +dir = File.dirname(__FILE__) +require "#{dir}/ruby_extensions/string" \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/ruby_extensions/string.rb b/vendor/gems/treetop-1.2.5/lib/treetop/ruby_extensions/string.rb new file mode 100755 index 0000000..da34212 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/ruby_extensions/string.rb @@ -0,0 +1,42 @@ +class String + def column_of(index) + return 1 if index == 0 + newline_index = rindex("\n", index - 1) + if newline_index + index - newline_index + else + index + 1 + end + end + + def line_of(index) + self[0...index].count("\n") + 1 + end + + unless method_defined?(:blank?) + def blank? + self == "" + end + end + + # The following methods are lifted from Facets 2.0.2 + def tabto(n) + if self =~ /^( *)\S/ + indent(n - $1.length) + else + self + end + end + + def indent(n) + if n >= 0 + gsub(/^/, ' ' * n) + else + gsub(/^ {0,#{-n}}/, "") + end + end + + def treetop_camelize + to_s.gsub(/\/(.?)/){ "::" + $1.upcase }.gsub(/(^|_)(.)/){ $2.upcase } + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/runtime.rb b/vendor/gems/treetop-1.2.5/lib/treetop/runtime.rb new file mode 100755 index 0000000..38a84f4 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/runtime.rb @@ -0,0 +1,5 @@ +dir = File.dirname(__FILE__) +require "#{dir}/runtime/compiled_parser" +require "#{dir}/runtime/syntax_node" +require "#{dir}/runtime/terminal_parse_failure" +require "#{dir}/runtime/interval_skip_list" diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/runtime/compiled_parser.rb b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/compiled_parser.rb new file mode 100755 index 0000000..605ec5f --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/compiled_parser.rb @@ -0,0 +1,95 @@ +module Treetop + module Runtime + class CompiledParser + include Treetop::Runtime + + attr_reader :input, :index, :terminal_failures, :max_terminal_failure_index + attr_writer :root + attr_accessor :consume_all_input + alias :consume_all_input? :consume_all_input + + def initialize + self.consume_all_input = true + end + + def parse(input, options = {}) + prepare_to_parse(input) + @index = options[:index] if options[:index] + result = send("_nt_#{root}") + return nil if (consume_all_input? && index != input.size) + return result + end + + def failure_index + max_terminal_failure_index + end + + def failure_line + terminal_failures && input.line_of(failure_index) + end + + def failure_column + terminal_failures && input.column_of(failure_index) + end + + def failure_reason + return nil unless (tf = terminal_failures) && tf.size > 0 + "Expected " + + (tf.size == 1 ? + tf[0].expected_string : + "one of #{tf.map{|f| f.expected_string}.uniq*', '}" + ) + + " at line #{failure_line}, column #{failure_column} (byte #{failure_index+1})" + + " after #{input[index...failure_index]}" + end + + + protected + + attr_reader :node_cache, :input_length + attr_writer :index + + def prepare_to_parse(input) + @input = input + @input_length = input.length + reset_index + @node_cache = Hash.new {|hash, key| hash[key] = Hash.new} + @terminal_failures = [] + @max_terminal_failure_index = 0 + end + + def reset_index + @index = 0 + end + + def parse_anything(node_class = SyntaxNode, inline_module = nil) + if index < input.length + result = instantiate_node(node_class,input, index...(index + 1)) + result.extend(inline_module) if inline_module + @index += 1 + result + else + terminal_parse_failure("any character") + end + end + + def instantiate_node(node_type,*args) + if node_type.respond_to? :new + node_type.new(*args) + else + SyntaxNode.new(*args).extend(node_type) + end + end + + def terminal_parse_failure(expected_string) + return nil if index < max_terminal_failure_index + if index > max_terminal_failure_index + @max_terminal_failure_index = index + @terminal_failures = [] + end + terminal_failures << TerminalParseFailure.new(index, expected_string) + return nil + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list.rb b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list.rb new file mode 100755 index 0000000..8f34379 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list.rb @@ -0,0 +1,4 @@ +dir = File.dirname(__FILE__) +require "#{dir}/interval_skip_list/interval_skip_list.rb" +require "#{dir}/interval_skip_list/head_node.rb" +require "#{dir}/interval_skip_list/node.rb" \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list/head_node.rb b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list/head_node.rb new file mode 100755 index 0000000..7cb0bab --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list/head_node.rb @@ -0,0 +1,15 @@ +class IntervalSkipList + class HeadNode + attr_reader :height, :forward, :forward_markers + + def initialize(height) + @height = height + @forward = Array.new(height, nil) + @forward_markers = Array.new(height) {|i| []} + end + + def top_level + height - 1 + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list/interval_skip_list.rb b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list/interval_skip_list.rb new file mode 100755 index 0000000..27b53e0 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list/interval_skip_list.rb @@ -0,0 +1,200 @@ +class IntervalSkipList + attr_reader :probability + + def initialize + @head = HeadNode.new(max_height) + @ranges = {} + @probability = 0.5 + end + + def max_height + 3 + end + + def empty? + head.forward[0].nil? + end + + def expire(range, length_change) + expired_markers, first_node_after_range = overlapping(range) + expired_markers.each { |marker| delete(marker) } + first_node_after_range.propagate_length_change(length_change) + end + + def overlapping(range) + markers, first_node = containing_with_node(range.first) + + cur_node = first_node + begin + markers.concat(cur_node.forward_markers.flatten) + cur_node = cur_node.forward[0] + end while cur_node.key < range.last + + return markers.uniq, cur_node + end + + def containing(n) + containing_with_node(n).first + end + + def insert(range, marker) + ranges[marker] = range + first_node = insert_node(range.first) + first_node.endpoint_of.push(marker) + last_node = insert_node(range.last) + last_node.endpoint_of.push(marker) + + cur_node = first_node + cur_level = first_node.top_level + while next_node_at_level_inside_range?(cur_node, cur_level, range) + while can_ascend_from?(cur_node, cur_level) && next_node_at_level_inside_range?(cur_node, cur_level + 1, range) + cur_level += 1 + end + cur_node = mark_forward_path_at_level(cur_node, cur_level, marker) + end + + while node_inside_range?(cur_node, range) + while can_descend_from?(cur_level) && next_node_at_level_outside_range?(cur_node, cur_level, range) + cur_level -= 1 + end + cur_node = mark_forward_path_at_level(cur_node, cur_level, marker) + end + end + + def delete(marker) + range = ranges[marker] + path_to_first_node = make_path + first_node = find(range.first, path_to_first_node) + + cur_node = first_node + cur_level = first_node.top_level + while next_node_at_level_inside_range?(cur_node, cur_level, range) + while can_ascend_from?(cur_node, cur_level) && next_node_at_level_inside_range?(cur_node, cur_level + 1, range) + cur_level += 1 + end + cur_node = unmark_forward_path_at_level(cur_node, cur_level, marker) + end + + while node_inside_range?(cur_node, range) + while can_descend_from?(cur_level) && next_node_at_level_outside_range?(cur_node, cur_level, range) + cur_level -= 1 + end + cur_node = unmark_forward_path_at_level(cur_node, cur_level, marker) + end + last_node = cur_node + + first_node.endpoint_of.delete(marker) + if first_node.endpoint_of.empty? + first_node.delete(path_to_first_node) + end + + last_node.endpoint_of.delete(marker) + if last_node.endpoint_of.empty? + path_to_last_node = make_path + find(range.last, path_to_last_node) + last_node.delete(path_to_last_node) + end + end + + protected + attr_reader :head, :ranges + + def insert_node(key) + path = make_path + found_node = find(key, path) + if found_node && found_node.key == key + return found_node + else + return Node.new(key, next_node_height, path) + end + end + + def containing_with_node(n) + containing = [] + cur_node = head + (max_height - 1).downto(0) do |cur_level| + while (next_node = cur_node.forward[cur_level]) && next_node.key <= n + cur_node = next_node + if cur_node.key == n + return containing + (cur_node.markers - cur_node.endpoint_of), cur_node + end + end + containing.concat(cur_node.forward_markers[cur_level]) + end + + return containing, cur_node + end + + def delete_node(key) + path = make_path + found_node = find(key, path) + found_node.delete(path) if found_node.key == key + end + + def find(key, path) + cur_node = head + (max_height - 1).downto(0) do |cur_level| + while (next_node = cur_node.forward[cur_level]) && next_node.key < key + cur_node = next_node + end + path[cur_level] = cur_node + end + cur_node.forward[0] + end + + def make_path + Array.new(max_height, nil) + end + + def next_node_height + height = 1 + while rand < probability && height < max_height + height += 1 + end + height + end + + def can_ascend_from?(node, level) + level < node.top_level + end + + def can_descend_from?(level) + level > 0 + end + + def node_inside_range?(node, range) + node.key < range.last + end + + def next_node_at_level_inside_range?(node, level, range) + node.forward[level] && node.forward[level].key <= range.last + end + + def next_node_at_level_outside_range?(node, level, range) + (node.forward[level].nil? || node.forward[level].key > range.last) + end + + def mark_forward_path_at_level(node, level, marker) + node.forward_markers[level].push(marker) + next_node = node.forward[level] + next_node.markers.push(marker) + node = next_node + end + + def unmark_forward_path_at_level(node, level, marker) + node.forward_markers[level].delete(marker) + next_node = node.forward[level] + next_node.markers.delete(marker) + node = next_node + end + + def nodes + nodes = [] + cur_node = head.forward[0] + until cur_node.nil? + nodes << cur_node + cur_node = cur_node.forward[0] + end + nodes + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list/node.rb b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list/node.rb new file mode 100755 index 0000000..a53edb2 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/interval_skip_list/node.rb @@ -0,0 +1,164 @@ +class IntervalSkipList + class Node < HeadNode + attr_accessor :key + attr_reader :markers, :endpoint_of + + def initialize(key, height, path) + super(height) + @key = key + @markers = [] + @endpoint_of = [] + update_forward_pointers(path) + promote_markers(path) + end + + def all_forward_markers + markers.flatten + end + + def delete(path) + 0.upto(top_level) do |i| + path[i].forward[i] = forward[i] + end + demote_markers(path) + end + + def propagate_length_change(length_change) + cur_node = self + while cur_node do + cur_node.key += length_change + cur_node = cur_node.forward[0] + end + end + + protected + + def update_forward_pointers(path) + 0.upto(top_level) do |i| + forward[i] = path[i].forward[i] + path[i].forward[i] = self + end + end + + def promote_markers(path) + promoted = [] + new_promoted = [] + 0.upto(top_level) do |i| + incoming_markers = path[i].forward_markers[i] + markers.concat(incoming_markers) + + incoming_markers.each do |marker| + if can_be_promoted_higher?(marker, i) + new_promoted.push(marker) + forward[i].delete_marker_from_path(marker, i, forward[i+1]) + else + forward_markers[i].push(marker) + end + end + + promoted.each do |marker| + if can_be_promoted_higher?(marker, i) + new_promoted.push(marker) + forward[i].delete_marker_from_path(marker, i, forward[i+1]) + else + forward_markers[i].push(marker) + end + end + + promoted = new_promoted + new_promoted = [] + end + end + + + def can_be_promoted_higher?(marker, level) + level < top_level && forward[level + 1] && forward[level + 1].markers.include?(marker) + end + + def delete_marker_from_path(marker, level, terminus) + cur_node = self + until cur_node == terminus + cur_node.forward_markers[level].delete(marker) + cur_node.markers.delete(marker) + cur_node = cur_node.forward[level] + end + end + + def demote_markers(path) + demote_inbound_markers(path) + demote_outbound_markers(path) + end + + def demote_inbound_markers(path) + demoted = [] + new_demoted = [] + + top_level.downto(0) do |i| + incoming_markers = path[i].forward_markers[i].dup + incoming_markers.each do |marker| + unless forward_node_with_marker_at_or_above_level?(marker, i) + path[i].forward_markers[i].delete(marker) + new_demoted.push(marker) + end + end + + demoted.each do |marker| + path[i + 1].place_marker_on_inbound_path(marker, i, path[i]) + + if forward[i].markers.include?(marker) + path[i].forward_markers[i].push(marker) + else + new_demoted.push(marker) + end + end + + demoted = new_demoted + new_demoted = [] + end + end + + def demote_outbound_markers(path) + demoted = [] + new_demoted = [] + + top_level.downto(0) do |i| + forward_markers[i].each do |marker| + new_demoted.push(marker) unless path[i].forward_markers[i].include?(marker) + end + + demoted.each do |marker| + forward[i].place_marker_on_outbound_path(marker, i, forward[i + 1]) + new_demoted.push(marker) unless path[i].forward_markers[i].include?(marker) + end + + demoted = new_demoted + new_demoted = [] + end + end + + def forward_node_with_marker_at_or_above_level?(marker, level) + level.upto(top_level) do |i| + return true if forward[i].markers.include?(marker) + end + false + end + + def place_marker_on_outbound_path(marker, level, terminus) + cur_node = self + until cur_node == terminus + cur_node.forward_markers[level].push(marker) + cur_node.markers.push(marker) + cur_node = cur_node.forward[level] + end + end + + def place_marker_on_inbound_path(marker, level, terminus) + cur_node = self + until cur_node == terminus + cur_node.forward_markers[level].push(marker) + cur_node = cur_node.forward[level] + cur_node.markers.push(marker) + end + end + end +end \ No newline at end of file diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/runtime/syntax_node.rb b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/syntax_node.rb new file mode 100755 index 0000000..1a61e35 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/syntax_node.rb @@ -0,0 +1,72 @@ +module Treetop + module Runtime + class SyntaxNode + attr_reader :input, :interval, :elements + attr_accessor :parent + + def initialize(input, interval, elements = nil) + @input = input + @interval = interval + if @elements = elements + elements.each do |element| + element.parent = self + end + end + end + + def terminal? + @elements.nil? + end + + def nonterminal? + !terminal? + end + + def text_value + input[interval] + end + + def empty? + interval.first == interval.last && interval.exclude_end? + end + + def extension_modules + local_extensions = + class < 0 + local_extensions + else + [] # There weren't any; must be a literal node + end + end + + def inspect(indent="") + em = extension_modules + interesting_methods = methods-[em.last ? em.last.methods : nil]-self.class.instance_methods + im = interesting_methods.size > 0 ? " (#{interesting_methods.join(",")})" : "" + tv = text_value + tv = "...#{tv[-20..-1]}" if tv.size > 20 + + indent + + self.class.to_s.sub(/.*:/,'') + + em.map{|m| "+"+m.to_s.sub(/.*:/,'')}*"" + + " offset=#{interval.first}" + + ", #{tv.inspect}" + + im + + (elements && elements.size > 0 ? + ":" + + (@elements||[]).map{|e| + begin + "\n"+e.inspect(indent+" ") + rescue # Defend against inspect not taking a parameter + "\n"+indent+" "+e.inspect + end + }.join("") : + "" + ) + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/runtime/terminal_parse_failure.rb b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/terminal_parse_failure.rb new file mode 100755 index 0000000..b87bdbb --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/terminal_parse_failure.rb @@ -0,0 +1,16 @@ +module Treetop + module Runtime + class TerminalParseFailure + attr_reader :index, :expected_string + + def initialize(index, expected_string) + @index = index + @expected_string = expected_string + end + + def to_s + "String matching #{expected_string} expected." + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/runtime/terminal_parse_failure_debug.rb b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/terminal_parse_failure_debug.rb new file mode 100755 index 0000000..3b52cca --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/terminal_parse_failure_debug.rb @@ -0,0 +1,21 @@ +module Treetop + module Runtime + class TerminalParseFailure + attr_reader :index + + def initialize(index, expected_string) + @index = index + @caller = caller + @expected_string = expected_string + end + + def expected_string + "#{@expected_string} from #{@caller.map{|s| s.sub(/\A.*:([0-9]+):in `([^']*)'.*/,'\2:\1')}*" from "}\n\t" + end + + def to_s + "String matching #{expected_string} expected." + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/runtime/terminal_syntax_node.rb b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/terminal_syntax_node.rb new file mode 100755 index 0000000..06c6816 --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/runtime/terminal_syntax_node.rb @@ -0,0 +1,17 @@ +module Treetop + module Runtime + class TerminalSyntaxNode < SyntaxNode + + def initialize(input, interval) + super(input, interval, []) + end + + def inspect(indent="") + indent+ + self.class.to_s.sub(/.*:/,'') + + " offset=#{interval.first}" + + " #{text_value.inspect}" + end + end + end +end diff --git a/vendor/gems/treetop-1.2.5/lib/treetop/version.rb b/vendor/gems/treetop-1.2.5/lib/treetop/version.rb new file mode 100755 index 0000000..519803a --- /dev/null +++ b/vendor/gems/treetop-1.2.5/lib/treetop/version.rb @@ -0,0 +1,9 @@ +module Treetop #:nodoc: + module VERSION #:nodoc: + MAJOR = 1 + MINOR = 2 + TINY = 5 + + STRING = [MAJOR, MINOR, TINY].join('.') + end +end