trxl 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +24 -0
 - data/README +143 -0
 - data/Rakefile +41 -0
 - data/VERSION +1 -0
 - data/lib/trxl.rb +5 -0
 - data/lib/trxl/trxl.rb +585 -0
 - data/lib/trxl/trxl_grammar.rb +8583 -0
 - data/lib/trxl/trxl_grammar.treetop +1394 -0
 - data/spec/spec.opts +4 -0
 - data/spec/spec_helper.rb +28 -0
 - data/spec/trxl/arithmetics_spec.rb +391 -0
 - data/spec/trxl/arrays_spec.rb +163 -0
 - data/spec/trxl/booleans_spec.rb +138 -0
 - data/spec/trxl/builtins_spec.rb +268 -0
 - data/spec/trxl/closures_spec.rb +244 -0
 - data/spec/trxl/comments_spec.rb +35 -0
 - data/spec/trxl/common_spec.rb +22 -0
 - data/spec/trxl/conditionals_spec.rb +454 -0
 - data/spec/trxl/constants_spec.rb +23 -0
 - data/spec/trxl/environment_spec.rb +117 -0
 - data/spec/trxl/hashes_spec.rb +62 -0
 - data/spec/trxl/numbers_spec.rb +27 -0
 - data/spec/trxl/ranges_spec.rb +81 -0
 - data/spec/trxl/require_spec.rb +50 -0
 - data/spec/trxl/stdlib_spec.rb +370 -0
 - data/spec/trxl/strings_spec.rb +1 -0
 - data/spec/trxl/variables_spec.rb +45 -0
 - data/trxl.gemspec +90 -0
 - metadata +119 -0
 
    
        data/.gitignore
    ADDED
    
    | 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            test_log
         
     | 
| 
      
 2 
     | 
    
         
            +
            pkg
         
     | 
| 
      
 3 
     | 
    
         
            +
            pkg/*
         
     | 
| 
      
 4 
     | 
    
         
            +
            */pkg/*
         
     | 
| 
      
 5 
     | 
    
         
            +
            bundle
         
     | 
| 
      
 6 
     | 
    
         
            +
            bundle/*
         
     | 
| 
      
 7 
     | 
    
         
            +
            doc
         
     | 
| 
      
 8 
     | 
    
         
            +
            *.log
         
     | 
| 
      
 9 
     | 
    
         
            +
            log
         
     | 
| 
      
 10 
     | 
    
         
            +
            !log*.rb
         
     | 
| 
      
 11 
     | 
    
         
            +
            */log
         
     | 
| 
      
 12 
     | 
    
         
            +
            log/*
         
     | 
| 
      
 13 
     | 
    
         
            +
            */log/*
         
     | 
| 
      
 14 
     | 
    
         
            +
            coverage
         
     | 
| 
      
 15 
     | 
    
         
            +
            */coverage
         
     | 
| 
      
 16 
     | 
    
         
            +
            lib/dm-more.rb
         
     | 
| 
      
 17 
     | 
    
         
            +
            *.db
         
     | 
| 
      
 18 
     | 
    
         
            +
            nbproject
         
     | 
| 
      
 19 
     | 
    
         
            +
            .DS_Store
         
     | 
| 
      
 20 
     | 
    
         
            +
            rspec_report.html
         
     | 
| 
      
 21 
     | 
    
         
            +
            *.swp
         
     | 
| 
      
 22 
     | 
    
         
            +
            _Yardoc
         
     | 
| 
      
 23 
     | 
    
         
            +
            */ri
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
    
        data/README
    ADDED
    
    | 
         @@ -0,0 +1,143 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 2 
     | 
    
         
            +
            1)  Built in operators:
         
     | 
| 
      
 3 
     | 
    
         
            +
                +,-,*,/,%,==,!=,<=,>=,<,>,;
         
     | 
| 
      
 4 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 5 
     | 
    
         
            +
            2)  Integers and floats in arithmetics:
         
     | 
| 
      
 6 
     | 
    
         
            +
                1 or 2.33333 or 0.34 or .34
         
     | 
| 
      
 7 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 8 
     | 
    
         
            +
            3)  Arbitrary nesting of parentheses:
         
     | 
| 
      
 9 
     | 
    
         
            +
                (1+2*(5+((3+4)*3)-6/2)+7*2)\n    => 61
         
     | 
| 
      
 10 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 11 
     | 
    
         
            +
            4)  Comments:
         
     | 
| 
      
 12 
     | 
    
         
            +
                # A comment until the end of the line
         
     | 
| 
      
 13 
     | 
    
         
            +
                /* A longer comment that
         
     | 
| 
      
 14 
     | 
    
         
            +
                   spans multiple lines
         
     | 
| 
      
 15 
     | 
    
         
            +
                 */
         
     | 
| 
      
 16 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 17 
     | 
    
         
            +
            5)  Built in keywords:
         
     | 
| 
      
 18 
     | 
    
         
            +
                TRUE,FALSE,NULL,IF,ELSE,END
         
     | 
| 
      
 19 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 20 
     | 
    
         
            +
            6)  Built in functions:
         
     | 
| 
      
 21 
     | 
    
         
            +
                HELP,ENV,SIZE,SPLIT,ROUND,MIN,MAX
         
     | 
| 
      
 22 
     | 
    
         
            +
                SUM,MULT,AVG, PRINT, PRINT_LINE
         
     | 
| 
      
 23 
     | 
    
         
            +
                TO_INT, TO_FLOAT, TO_ARRAY
         
     | 
| 
      
 24 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 25 
     | 
    
         
            +
            7)  Standard library functions:
         
     | 
| 
      
 26 
     | 
    
         
            +
                Use to iterate over Arrays or Strings
         
     | 
| 
      
 27 
     | 
    
         
            +
                FOREACH_IN, INJECT
         
     | 
| 
      
 28 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 29 
     | 
    
         
            +
            8)  Access the current environment:
         
     | 
| 
      
 30 
     | 
    
         
            +
                ENV; (your output may differ)
         
     | 
| 
      
 31 
     | 
    
         
            +
                => { :a => 3, :foo => 5 }
         
     | 
| 
      
 32 
     | 
    
         
            +
                Given the following environment:
         
     | 
| 
      
 33 
     | 
    
         
            +
                { :a => 1, :b => 2, :c => 3 }
         
     | 
| 
      
 34 
     | 
    
         
            +
                ENV['a']
         
     | 
| 
      
 35 
     | 
    
         
            +
                => 1
         
     | 
| 
      
 36 
     | 
    
         
            +
                ENV['a'..'b']
         
     | 
| 
      
 37 
     | 
    
         
            +
                => { :a => 1, :b => 2 }
         
     | 
| 
      
 38 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 39 
     | 
    
         
            +
            9)  Numeric variables and literals
         
     | 
| 
      
 40 
     | 
    
         
            +
                3;
         
     | 
| 
      
 41 
     | 
    
         
            +
                => 3
         
     | 
| 
      
 42 
     | 
    
         
            +
                a = 3;
         
     | 
| 
      
 43 
     | 
    
         
            +
                => 3
         
     | 
| 
      
 44 
     | 
    
         
            +
                a;
         
     | 
| 
      
 45 
     | 
    
         
            +
                => 3
         
     | 
| 
      
 46 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 47 
     | 
    
         
            +
            10) String variables and literals
         
     | 
| 
      
 48 
     | 
    
         
            +
                "This is a string";    
         
     | 
| 
      
 49 
     | 
    
         
            +
                => "This is a string";
         
     | 
| 
      
 50 
     | 
    
         
            +
                'This is a string';
         
     | 
| 
      
 51 
     | 
    
         
            +
                => "This is a string";
         
     | 
| 
      
 52 
     | 
    
         
            +
                s1 = "This is a string"; s1;
         
     | 
| 
      
 53 
     | 
    
         
            +
                => "This is a string"
         
     | 
| 
      
 54 
     | 
    
         
            +
                s2 = 'This is a string'; s2;
         
     | 
| 
      
 55 
     | 
    
         
            +
                => "This is a string"
         
     | 
| 
      
 56 
     | 
    
         
            +
                SIZE(s1);
         
     | 
| 
      
 57 
     | 
    
         
            +
                => 16
         
     | 
| 
      
 58 
     | 
    
         
            +
                SIZE("foo");
         
     | 
| 
      
 59 
     | 
    
         
            +
                => 3
         
     | 
| 
      
 60 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 61 
     | 
    
         
            +
            11) Variables and closure applications
         
     | 
| 
      
 62 
     | 
    
         
            +
                a = 3; foo = 5;
         
     | 
| 
      
 63 
     | 
    
         
            +
                calc = fun(x,y) { (x + y) * a + foo };
         
     | 
| 
      
 64 
     | 
    
         
            +
                calc(2,2);
         
     | 
| 
      
 65 
     | 
    
         
            +
                => 17
         
     | 
| 
      
 66 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 67 
     | 
    
         
            +
            12) Array variables and literals
         
     | 
| 
      
 68 
     | 
    
         
            +
                arr = [1, [fun(){2}()], fun(x){x}(3)]
         
     | 
| 
      
 69 
     | 
    
         
            +
                SIZE(arr);
         
     | 
| 
      
 70 
     | 
    
         
            +
                => 3
         
     | 
| 
      
 71 
     | 
    
         
            +
                SIZE([1,2,3]);
         
     | 
| 
      
 72 
     | 
    
         
            +
                => 3
         
     | 
| 
      
 73 
     | 
    
         
            +
                [1,2,3] + [4,[5,6]];
         
     | 
| 
      
 74 
     | 
    
         
            +
                => [1,2,3,4,[5,6]]
         
     | 
| 
      
 75 
     | 
    
         
            +
                [1,2,3] - [[1],2,3];
         
     | 
| 
      
 76 
     | 
    
         
            +
                => [1]
         
     | 
| 
      
 77 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 78 
     | 
    
         
            +
            13) Hash variables and literals
         
     | 
| 
      
 79 
     | 
    
         
            +
                h = { 1 => fun(){2}(), 'a' => 'foo' }
         
     | 
| 
      
 80 
     | 
    
         
            +
                SIZE(h);
         
     | 
| 
      
 81 
     | 
    
         
            +
                => 2
         
     | 
| 
      
 82 
     | 
    
         
            +
                h[1];
         
     | 
| 
      
 83 
     | 
    
         
            +
                => 'fun(){2}()'
         
     | 
| 
      
 84 
     | 
    
         
            +
                h['a'];
         
     | 
| 
      
 85 
     | 
    
         
            +
                => 'foo'
         
     | 
| 
      
 86 
     | 
    
         
            +
                SIZE({ 1 => 2});
         
     | 
| 
      
 87 
     | 
    
         
            +
                => 1
         
     | 
| 
      
 88 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 89 
     | 
    
         
            +
            14) Range variables and literals
         
     | 
| 
      
 90 
     | 
    
         
            +
                range_including_upper = 1..5
         
     | 
| 
      
 91 
     | 
    
         
            +
                => [ 1, 2, 3, 4, 5 ]
         
     | 
| 
      
 92 
     | 
    
         
            +
                SIZE(range_including_upper);
         
     | 
| 
      
 93 
     | 
    
         
            +
                => 5
         
     | 
| 
      
 94 
     | 
    
         
            +
                range_excluding_upper = 1...5
         
     | 
| 
      
 95 
     | 
    
         
            +
                => [ 1, 2, 3, 4 ]
         
     | 
| 
      
 96 
     | 
    
         
            +
                SIZE(range_excluding_upper);
         
     | 
| 
      
 97 
     | 
    
         
            +
                => 4
         
     | 
| 
      
 98 
     | 
    
         
            +
                SIZE([1..5);
         
     | 
| 
      
 99 
     | 
    
         
            +
                => 5
         
     | 
| 
      
 100 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 101 
     | 
    
         
            +
            15) Conditional branching and recursion:
         
     | 
| 
      
 102 
     | 
    
         
            +
                factorial = fun(x) {      
         
     | 
| 
      
 103 
     | 
    
         
            +
                  if(x == 0)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    1
         
     | 
| 
      
 105 
     | 
    
         
            +
                  else
         
     | 
| 
      
 106 
     | 
    
         
            +
                    x * factorial(x - 1)
         
     | 
| 
      
 107 
     | 
    
         
            +
                  end
         
     | 
| 
      
 108 
     | 
    
         
            +
                }
         
     | 
| 
      
 109 
     | 
    
         
            +
                factorial(5);
         
     | 
| 
      
 110 
     | 
    
         
            +
                => 120
         
     | 
| 
      
 111 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 112 
     | 
    
         
            +
            16) Conditional branching:
         
     | 
| 
      
 113 
     | 
    
         
            +
                foo = fun(x) {
         
     | 
| 
      
 114 
     | 
    
         
            +
                  if(x == 0)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    0
         
     | 
| 
      
 116 
     | 
    
         
            +
                  elsif(x == 1)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    1
         
     | 
| 
      
 118 
     | 
    
         
            +
                  else
         
     | 
| 
      
 119 
     | 
    
         
            +
                    2
         
     | 
| 
      
 120 
     | 
    
         
            +
                  end
         
     | 
| 
      
 121 
     | 
    
         
            +
                }
         
     | 
| 
      
 122 
     | 
    
         
            +
                foo(0);
         
     | 
| 
      
 123 
     | 
    
         
            +
                => 0
         
     | 
| 
      
 124 
     | 
    
         
            +
                foo(1);
         
     | 
| 
      
 125 
     | 
    
         
            +
                => 1
         
     | 
| 
      
 126 
     | 
    
         
            +
                foo(2);
         
     | 
| 
      
 127 
     | 
    
         
            +
                => 2
         
     | 
| 
      
 128 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 129 
     | 
    
         
            +
            17) case expressions:
         
     | 
| 
      
 130 
     | 
    
         
            +
                foo = fun(x) {
         
     | 
| 
      
 131 
     | 
    
         
            +
                  case x
         
     | 
| 
      
 132 
     | 
    
         
            +
                  when 0 then 0
         
     | 
| 
      
 133 
     | 
    
         
            +
                  when 1 then 1
         
     | 
| 
      
 134 
     | 
    
         
            +
                  when 2 then 2
         
     | 
| 
      
 135 
     | 
    
         
            +
                  else 3
         
     | 
| 
      
 136 
     | 
    
         
            +
                  end
         
     | 
| 
      
 137 
     | 
    
         
            +
                }
         
     | 
| 
      
 138 
     | 
    
         
            +
                foo(1);
         
     | 
| 
      
 139 
     | 
    
         
            +
                => 1
         
     | 
| 
      
 140 
     | 
    
         
            +
                foo(3);
         
     | 
| 
      
 141 
     | 
    
         
            +
                => 3
         
     | 
| 
      
 142 
     | 
    
         
            +
            -----------------------------------------
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rake'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            begin
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              gem 'jeweler', '>= 1.4'
         
     | 
| 
      
 7 
     | 
    
         
            +
              require 'jeweler'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              Jeweler::Tasks.new do |gem|
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                gem.name        = "trxl"
         
     | 
| 
      
 12 
     | 
    
         
            +
                gem.summary     = 'A specced little language written with ruby and treetop.'
         
     | 
| 
      
 13 
     | 
    
         
            +
                gem.description = 'A specced little language written with ruby and treetop. It has lambdas, recursion, conditionals, arrays, hashes, ranges, strings, arithmetics and some other stuff. It even has a small code import facility.'
         
     | 
| 
      
 14 
     | 
    
         
            +
                gem.email       = "gamsnjaga [at] gmail [dot] com"
         
     | 
| 
      
 15 
     | 
    
         
            +
                gem.homepage    = "http://github.com/snusnu/trxl"
         
     | 
| 
      
 16 
     | 
    
         
            +
                gem.authors     = ['Martin Gamsjaeger (snusnu)', 'Michael Aufreiter']
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                # Runtime dependencies
         
     | 
| 
      
 19 
     | 
    
         
            +
                gem.add_dependency 'treetop', '>= 1.4'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                # Development dependencies
         
     | 
| 
      
 22 
     | 
    
         
            +
                gem.add_development_dependency 'rspec', '>= 1.2.9'
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              Jeweler::GemcutterTasks.new
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 29 
     | 
    
         
            +
              puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler'
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            require 'spec/rake/spectask'
         
     | 
| 
      
 33 
     | 
    
         
            +
            Spec::Rake::SpecTask.new(:spec) do |spec|
         
     | 
| 
      
 34 
     | 
    
         
            +
              spec.pattern    = 'spec/**/*_spec.rb'
         
     | 
| 
      
 35 
     | 
    
         
            +
              spec.libs      << 'lib' << 'spec'
         
     | 
| 
      
 36 
     | 
    
         
            +
              spec.spec_opts << '--options' << 'spec/spec.opts'
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            task :default => :spec
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
    
        data/VERSION
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            0.1.5
         
     | 
    
        data/lib/trxl.rb
    ADDED
    
    
    
        data/lib/trxl/trxl.rb
    ADDED
    
    | 
         @@ -0,0 +1,585 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # load treetop grammar
         
     | 
| 
      
 2 
     | 
    
         
            +
            # this is done independent of RAILS_ROOT to allow easy
         
     | 
| 
      
 3 
     | 
    
         
            +
            # speccing outside of rails context
         
     | 
| 
      
 4 
     | 
    
         
            +
            # TODO once stable, replace this with a simple require
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            # reopen treetop generated module
         
     | 
| 
      
 8 
     | 
    
         
            +
            module Trxl
         
     | 
| 
      
 9 
     | 
    
         
            +
              
         
     | 
| 
      
 10 
     | 
    
         
            +
              class TrxlException < Exception; end
         
     | 
| 
      
 11 
     | 
    
         
            +
              class InternalError < TrxlException; end
         
     | 
| 
      
 12 
     | 
    
         
            +
              class FatalParseError < TrxlException; end
         
     | 
| 
      
 13 
     | 
    
         
            +
              class DivisionByZeroError < FatalParseError; end
         
     | 
| 
      
 14 
     | 
    
         
            +
              class MissingFormulaException < TrxlException; end
         
     | 
| 
      
 15 
     | 
    
         
            +
              class MissingVariableException < TrxlException; end
         
     | 
| 
      
 16 
     | 
    
         
            +
              class InvalidOperationException < TrxlException; end
         
     | 
| 
      
 17 
     | 
    
         
            +
              class InvalidArgumentException < TrxlException; end
         
     | 
| 
      
 18 
     | 
    
         
            +
              class WrongNumberOfArgumentsException < TrxlException; end
         
     | 
| 
      
 19 
     | 
    
         
            +
              
         
     | 
| 
      
 20 
     | 
    
         
            +
              class MissingLibraryException < TrxlException; end
         
     | 
| 
      
 21 
     | 
    
         
            +
              class NotImplementedException < TrxlException; end
         
     | 
| 
      
 22 
     | 
    
         
            +
              
         
     | 
| 
      
 23 
     | 
    
         
            +
              class ExitScopeNotAllowedException < TrxlException; end
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
              class Assignment < Treetop::Runtime::SyntaxNode; end
         
     | 
| 
      
 26 
     | 
    
         
            +
              class Variable < Treetop::Runtime::SyntaxNode; end
         
     | 
| 
      
 27 
     | 
    
         
            +
              
         
     | 
| 
      
 28 
     | 
    
         
            +
              
         
     | 
| 
      
 29 
     | 
    
         
            +
              
         
     | 
| 
      
 30 
     | 
    
         
            +
              class Environment
         
     | 
| 
      
 31 
     | 
    
         
            +
                
         
     | 
| 
      
 32 
     | 
    
         
            +
                # called when parsing starts
         
     | 
| 
      
 33 
     | 
    
         
            +
                def initialize(local_env = {})
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @stack = [ local_env ]
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
                
         
     | 
| 
      
 37 
     | 
    
         
            +
                def enter_scope
         
     | 
| 
      
 38 
     | 
    
         
            +
                  push #peek.dup
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
                
         
     | 
| 
      
 41 
     | 
    
         
            +
                def exit_scope
         
     | 
| 
      
 42 
     | 
    
         
            +
                  pop
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
                
         
     | 
| 
      
 45 
     | 
    
         
            +
                def local
         
     | 
| 
      
 46 
     | 
    
         
            +
                  peek
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
                
         
     | 
| 
      
 49 
     | 
    
         
            +
                
         
     | 
| 
      
 50 
     | 
    
         
            +
                def depth
         
     | 
| 
      
 51 
     | 
    
         
            +
                  @stack.size
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
                
         
     | 
| 
      
 54 
     | 
    
         
            +
                def merge(other_env)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  self.class.new(local.merge(other_env))
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
                
         
     | 
| 
      
 58 
     | 
    
         
            +
                def merge!(other_env)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  local.merge!(other_env); self
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
                
         
     | 
| 
      
 62 
     | 
    
         
            +
                
         
     | 
| 
      
 63 
     | 
    
         
            +
                def [](variable)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  var = variable.to_sym
         
     | 
| 
      
 65 
     | 
    
         
            +
                  @stack.each do |env|
         
     | 
| 
      
 66 
     | 
    
         
            +
                    if env.has_key?(var)
         
     | 
| 
      
 67 
     | 
    
         
            +
                      return env[var]
         
     | 
| 
      
 68 
     | 
    
         
            +
                    end
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
                  nil
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                # FIXME find out why map definition doesn't work
         
     | 
| 
      
 74 
     | 
    
         
            +
                def []=(variable, value)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  var = variable.to_sym
         
     | 
| 
      
 76 
     | 
    
         
            +
                  # search all scopes
         
     | 
| 
      
 77 
     | 
    
         
            +
                  @stack.each do |env|
         
     | 
| 
      
 78 
     | 
    
         
            +
                    if env.has_key?(var)
         
     | 
| 
      
 79 
     | 
    
         
            +
                      return env[var] = value 
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
                  # not found, assign it in local scope
         
     | 
| 
      
 83 
     | 
    
         
            +
                  local[var] = value
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
                
         
     | 
| 
      
 86 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 87 
     | 
    
         
            +
                  @stack.inject([]) do |stack, env|
         
     | 
| 
      
 88 
     | 
    
         
            +
                    stack << env.inspect
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end.join(',')
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
                
         
     | 
| 
      
 92 
     | 
    
         
            +
                def empty?
         
     | 
| 
      
 93 
     | 
    
         
            +
                  @stack.size == 1 ? peek.empty? : @stack.all? { |h| h.empty? }
         
     | 
| 
      
 94 
     | 
    
         
            +
                end
         
     | 
| 
      
 95 
     | 
    
         
            +
                
         
     | 
| 
      
 96 
     | 
    
         
            +
                def has_key?(key)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  @stack.any? { |env| env.has_key?(key.to_sym) }
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
                
         
     | 
| 
      
 100 
     | 
    
         
            +
                def select(&block)
         
     | 
| 
      
 101 
     | 
    
         
            +
                  @stack.inject([]) do |memo, env|
         
     | 
| 
      
 102 
     | 
    
         
            +
                    memo << env.select(&block)
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end[0]
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
                
         
     | 
| 
      
 106 
     | 
    
         
            +
                def add_library(name)
         
     | 
| 
      
 107 
     | 
    
         
            +
                  (@libraries || []) << name.to_sym
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
                
         
     | 
| 
      
 110 
     | 
    
         
            +
                def library_included?(name)
         
     | 
| 
      
 111 
     | 
    
         
            +
                  @libraries ? @libraries.include?(name.to_sym) : false
         
     | 
| 
      
 112 
     | 
    
         
            +
                end
         
     | 
| 
      
 113 
     | 
    
         
            +
                
         
     | 
| 
      
 114 
     | 
    
         
            +
                def libraries
         
     | 
| 
      
 115 
     | 
    
         
            +
                  @libraries.dup # don't allow modifications outside
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
                
         
     | 
| 
      
 118 
     | 
    
         
            +
                protected
         
     | 
| 
      
 119 
     | 
    
         
            +
                
         
     | 
| 
      
 120 
     | 
    
         
            +
                # called when a new scope is entered
         
     | 
| 
      
 121 
     | 
    
         
            +
                def push(local_env = {})
         
     | 
| 
      
 122 
     | 
    
         
            +
                  @stack.insert(0, local_env)
         
     | 
| 
      
 123 
     | 
    
         
            +
                end
         
     | 
| 
      
 124 
     | 
    
         
            +
                
         
     | 
| 
      
 125 
     | 
    
         
            +
                # called when a scope is left
         
     | 
| 
      
 126 
     | 
    
         
            +
                def pop
         
     | 
| 
      
 127 
     | 
    
         
            +
                  if depth > 1
         
     | 
| 
      
 128 
     | 
    
         
            +
                    @stack.shift
         
     | 
| 
      
 129 
     | 
    
         
            +
                  else
         
     | 
| 
      
 130 
     | 
    
         
            +
                    raise Trxl::ExitScopeNotAllowedException, "cannot pop toplevel environment"
         
     | 
| 
      
 131 
     | 
    
         
            +
                  end
         
     | 
| 
      
 132 
     | 
    
         
            +
                end
         
     | 
| 
      
 133 
     | 
    
         
            +
                
         
     | 
| 
      
 134 
     | 
    
         
            +
                # always the local environment
         
     | 
| 
      
 135 
     | 
    
         
            +
                def peek
         
     | 
| 
      
 136 
     | 
    
         
            +
                  @stack[0]
         
     | 
| 
      
 137 
     | 
    
         
            +
                end
         
     | 
| 
      
 138 
     | 
    
         
            +
                
         
     | 
| 
      
 139 
     | 
    
         
            +
              end
         
     | 
| 
      
 140 
     | 
    
         
            +
              
         
     | 
| 
      
 141 
     | 
    
         
            +
              class Function < Treetop::Runtime::SyntaxNode
         
     | 
| 
      
 142 
     | 
    
         
            +
                
         
     | 
| 
      
 143 
     | 
    
         
            +
                class Closure
         
     | 
| 
      
 144 
     | 
    
         
            +
                  attr_reader :env, :function
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                  def initialize(function, env = Environment.new)
         
     | 
| 
      
 147 
     | 
    
         
            +
                    @function = function
         
     | 
| 
      
 148 
     | 
    
         
            +
                    @env = env
         
     | 
| 
      
 149 
     | 
    
         
            +
                  end
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
                  def apply(args)
         
     | 
| 
      
 152 
     | 
    
         
            +
                    env.enter_scope
         
     | 
| 
      
 153 
     | 
    
         
            +
                    return_value = function.body.eval(function.formal_parameter_list.bind(args, env))
         
     | 
| 
      
 154 
     | 
    
         
            +
                    env.exit_scope
         
     | 
| 
      
 155 
     | 
    
         
            +
                    return_value
         
     | 
| 
      
 156 
     | 
    
         
            +
                  end
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                  def to_s(other_env = Environment.new)
         
     | 
| 
      
 159 
     | 
    
         
            +
                    function.text_value #"fun#{function.formal_parameter_list.to_s(env)} {#{function.body.to_s(other_env.merge(env.local))}}"
         
     | 
| 
      
 160 
     | 
    
         
            +
                  end
         
     | 
| 
      
 161 
     | 
    
         
            +
                end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                def eval(env = Environment.new)
         
     | 
| 
      
 164 
     | 
    
         
            +
                  Closure.new(self, env)
         
     | 
| 
      
 165 
     | 
    
         
            +
                end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                def to_s(env = Environment.new)
         
     | 
| 
      
 168 
     | 
    
         
            +
                  text_value #eval(env).to_s(env)
         
     | 
| 
      
 169 
     | 
    
         
            +
                end
         
     | 
| 
      
 170 
     | 
    
         
            +
              end
         
     | 
| 
      
 171 
     | 
    
         
            +
              
         
     | 
| 
      
 172 
     | 
    
         
            +
              class BinaryOperation < Treetop::Runtime::SyntaxNode
         
     | 
| 
      
 173 
     | 
    
         
            +
                
         
     | 
| 
      
 174 
     | 
    
         
            +
                def eval(env = Environment.new)
         
     | 
| 
      
 175 
     | 
    
         
            +
                  apply(operand_1.eval(env), operand_2.eval(env))
         
     | 
| 
      
 176 
     | 
    
         
            +
                end
         
     | 
| 
      
 177 
     | 
    
         
            +
                
         
     | 
| 
      
 178 
     | 
    
         
            +
                def apply(a, b)
         
     | 
| 
      
 179 
     | 
    
         
            +
                  operator.apply(a, b)
         
     | 
| 
      
 180 
     | 
    
         
            +
                end
         
     | 
| 
      
 181 
     | 
    
         
            +
                
         
     | 
| 
      
 182 
     | 
    
         
            +
                def to_s(env = Environment.new)
         
     | 
| 
      
 183 
     | 
    
         
            +
                  "#{operand_1.to_s(env)} #{operator.text_value} #{operand_2.to_s(env)}"
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
                
         
     | 
| 
      
 186 
     | 
    
         
            +
              end
         
     | 
| 
      
 187 
     | 
    
         
            +
              
         
     | 
| 
      
 188 
     | 
    
         
            +
              module BinaryOperatorSupport
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                def lhs_nil_allowed?
         
     | 
| 
      
 191 
     | 
    
         
            +
                  raise InternalError, "Implement BinaryOperaterSupport#lhs_nil_allowed?"
         
     | 
| 
      
 192 
     | 
    
         
            +
                end
         
     | 
| 
      
 193 
     | 
    
         
            +
                
         
     | 
| 
      
 194 
     | 
    
         
            +
                def rhs_nil_allowed?
         
     | 
| 
      
 195 
     | 
    
         
            +
                  raise InternalError, "Implement BinaryOperaterSupport#rhs_nil_allowed?"
         
     | 
| 
      
 196 
     | 
    
         
            +
                end
         
     | 
| 
      
 197 
     | 
    
         
            +
                
         
     | 
| 
      
 198 
     | 
    
         
            +
                def nils_allowed?
         
     | 
| 
      
 199 
     | 
    
         
            +
                  lhs_nil_allowed? && rhs_nil_allowed?
         
     | 
| 
      
 200 
     | 
    
         
            +
                end
         
     | 
| 
      
 201 
     | 
    
         
            +
                
         
     | 
| 
      
 202 
     | 
    
         
            +
                def apply(a, b)
         
     | 
| 
      
 203 
     | 
    
         
            +
                  if a.nil?
         
     | 
| 
      
 204 
     | 
    
         
            +
                    if b.nil?
         
     | 
| 
      
 205 
     | 
    
         
            +
                      if nils_allowed?
         
     | 
| 
      
 206 
     | 
    
         
            +
                        perform_apply(a, b)
         
     | 
| 
      
 207 
     | 
    
         
            +
                      else
         
     | 
| 
      
 208 
     | 
    
         
            +
                        raise InvalidArgumentException, "Both operands MUST NOT be NULL"
         
     | 
| 
      
 209 
     | 
    
         
            +
                      end
         
     | 
| 
      
 210 
     | 
    
         
            +
                    else
         
     | 
| 
      
 211 
     | 
    
         
            +
                      if lhs_nil_allowed?
         
     | 
| 
      
 212 
     | 
    
         
            +
                        perform_apply(a, b)
         
     | 
| 
      
 213 
     | 
    
         
            +
                      else
         
     | 
| 
      
 214 
     | 
    
         
            +
                        raise InvalidArgumentException, "LHS operand MUST NOT be NULL"
         
     | 
| 
      
 215 
     | 
    
         
            +
                      end
         
     | 
| 
      
 216 
     | 
    
         
            +
                    end
         
     | 
| 
      
 217 
     | 
    
         
            +
                  else
         
     | 
| 
      
 218 
     | 
    
         
            +
                    if b.nil?
         
     | 
| 
      
 219 
     | 
    
         
            +
                      if rhs_nil_allowed?
         
     | 
| 
      
 220 
     | 
    
         
            +
                        perform_apply(a, b)
         
     | 
| 
      
 221 
     | 
    
         
            +
                      else
         
     | 
| 
      
 222 
     | 
    
         
            +
                        raise InvalidArgumentException, "RHS operand MUST NOT be NULL"
         
     | 
| 
      
 223 
     | 
    
         
            +
                      end
         
     | 
| 
      
 224 
     | 
    
         
            +
                    else
         
     | 
| 
      
 225 
     | 
    
         
            +
                      perform_apply(a, b)
         
     | 
| 
      
 226 
     | 
    
         
            +
                    end
         
     | 
| 
      
 227 
     | 
    
         
            +
                  end 
         
     | 
| 
      
 228 
     | 
    
         
            +
                end
         
     | 
| 
      
 229 
     | 
    
         
            +
                
         
     | 
| 
      
 230 
     | 
    
         
            +
                def perform_apply(a, b)
         
     | 
| 
      
 231 
     | 
    
         
            +
                  if a.respond_to?(ruby_operator)
         
     | 
| 
      
 232 
     | 
    
         
            +
                    a.send(ruby_operator, b)
         
     | 
| 
      
 233 
     | 
    
         
            +
                  else
         
     | 
| 
      
 234 
     | 
    
         
            +
                    _a = a ? (a.is_a?(String) ? "'#{a}'" : a) : false
         
     | 
| 
      
 235 
     | 
    
         
            +
                    _b = b ? (b.is_a?(String) ? "'#{b}'" : b) : false
         
     | 
| 
      
 236 
     | 
    
         
            +
                    eval "#{_a} #{ruby_operator} #{_b}"
         
     | 
| 
      
 237 
     | 
    
         
            +
                  end
         
     | 
| 
      
 238 
     | 
    
         
            +
                end
         
     | 
| 
      
 239 
     | 
    
         
            +
                
         
     | 
| 
      
 240 
     | 
    
         
            +
                def ruby_operator
         
     | 
| 
      
 241 
     | 
    
         
            +
                  text_value
         
     | 
| 
      
 242 
     | 
    
         
            +
                end
         
     | 
| 
      
 243 
     | 
    
         
            +
                
         
     | 
| 
      
 244 
     | 
    
         
            +
              end
         
     | 
| 
      
 245 
     | 
    
         
            +
              
         
     | 
| 
      
 246 
     | 
    
         
            +
              class NilRejectingOperator < Treetop::Runtime::SyntaxNode
         
     | 
| 
      
 247 
     | 
    
         
            +
                
         
     | 
| 
      
 248 
     | 
    
         
            +
                include BinaryOperatorSupport
         
     | 
| 
      
 249 
     | 
    
         
            +
                
         
     | 
| 
      
 250 
     | 
    
         
            +
                def lhs_nil_allowed?
         
     | 
| 
      
 251 
     | 
    
         
            +
                  false
         
     | 
| 
      
 252 
     | 
    
         
            +
                end
         
     | 
| 
      
 253 
     | 
    
         
            +
                
         
     | 
| 
      
 254 
     | 
    
         
            +
                def rhs_nil_allowed?
         
     | 
| 
      
 255 
     | 
    
         
            +
                  false
         
     | 
| 
      
 256 
     | 
    
         
            +
                end
         
     | 
| 
      
 257 
     | 
    
         
            +
                
         
     | 
| 
      
 258 
     | 
    
         
            +
              end
         
     | 
| 
      
 259 
     | 
    
         
            +
              
         
     | 
| 
      
 260 
     | 
    
         
            +
              class NilAcceptingOperator < Treetop::Runtime::SyntaxNode
         
     | 
| 
      
 261 
     | 
    
         
            +
                
         
     | 
| 
      
 262 
     | 
    
         
            +
                include BinaryOperatorSupport
         
     | 
| 
      
 263 
     | 
    
         
            +
                
         
     | 
| 
      
 264 
     | 
    
         
            +
                def lhs_nil_allowed?
         
     | 
| 
      
 265 
     | 
    
         
            +
                  true
         
     | 
| 
      
 266 
     | 
    
         
            +
                end
         
     | 
| 
      
 267 
     | 
    
         
            +
                
         
     | 
| 
      
 268 
     | 
    
         
            +
                def rhs_nil_allowed?
         
     | 
| 
      
 269 
     | 
    
         
            +
                  true
         
     | 
| 
      
 270 
     | 
    
         
            +
                end
         
     | 
| 
      
 271 
     | 
    
         
            +
                
         
     | 
| 
      
 272 
     | 
    
         
            +
              end
         
     | 
| 
      
 273 
     | 
    
         
            +
              
         
     | 
| 
      
 274 
     | 
    
         
            +
              
         
     | 
| 
      
 275 
     | 
    
         
            +
              class OffsetAccessExpression < Treetop::Runtime::SyntaxNode
         
     | 
| 
      
 276 
     | 
    
         
            +
                
         
     | 
| 
      
 277 
     | 
    
         
            +
                def left_associative_apply(ruby_object, offsets)
         
     | 
| 
      
 278 
     | 
    
         
            +
                  offsets.inject(ruby_object) { |obj, offset| obj = obj[offset] }
         
     | 
| 
      
 279 
     | 
    
         
            +
                end
         
     | 
| 
      
 280 
     | 
    
         
            +
                  
         
     | 
| 
      
 281 
     | 
    
         
            +
              end
         
     | 
| 
      
 282 
     | 
    
         
            +
              
         
     | 
| 
      
 283 
     | 
    
         
            +
              class RequireDirective < Treetop::Runtime::SyntaxNode
         
     | 
| 
      
 284 
     | 
    
         
            +
                
         
     | 
| 
      
 285 
     | 
    
         
            +
                def eval(env = Environment.new)
         
     | 
| 
      
 286 
     | 
    
         
            +
                  library = ((l = load_library(env))[-1..-1]) == ';' ? "#{l} ENV" : "#{l}; ENV"
         
     | 
| 
      
 287 
     | 
    
         
            +
                  unless env.library_included?(identifier(env))
         
     | 
| 
      
 288 
     | 
    
         
            +
                    env.merge!(Calculator.new.eval(library, env).local)
         
     | 
| 
      
 289 
     | 
    
         
            +
                    env.add_library(identifier(env))
         
     | 
| 
      
 290 
     | 
    
         
            +
                  end
         
     | 
| 
      
 291 
     | 
    
         
            +
                  env
         
     | 
| 
      
 292 
     | 
    
         
            +
                end
         
     | 
| 
      
 293 
     | 
    
         
            +
                
         
     | 
| 
      
 294 
     | 
    
         
            +
                def identifier(env = Environment.new)
         
     | 
| 
      
 295 
     | 
    
         
            +
                  @identifier ||= string_literal.eval(env)
         
     | 
| 
      
 296 
     | 
    
         
            +
                end
         
     | 
| 
      
 297 
     | 
    
         
            +
                
         
     | 
| 
      
 298 
     | 
    
         
            +
                # override this in subclasses    
         
     | 
| 
      
 299 
     | 
    
         
            +
                def load_library(env = Environment.new)
         
     | 
| 
      
 300 
     | 
    
         
            +
                  path = identifier(env).split('/')
         
     | 
| 
      
 301 
     | 
    
         
            +
                  if path[0] == ('stdlib')
         
     | 
| 
      
 302 
     | 
    
         
            +
                    if optimize_stdlib_access?
         
     | 
| 
      
 303 
     | 
    
         
            +
                      if path.size == 2
         
     | 
| 
      
 304 
     | 
    
         
            +
                        const = path[1].upcase
         
     | 
| 
      
 305 
     | 
    
         
            +
                        if Trxl::StdLib.constants.include?(const)
         
     | 
| 
      
 306 
     | 
    
         
            +
                          Calculator.stdlib(const)
         
     | 
| 
      
 307 
     | 
    
         
            +
                        else
         
     | 
| 
      
 308 
     | 
    
         
            +
                          raise MissingLibraryException, "Failed to load '#{identifier}'"
         
     | 
| 
      
 309 
     | 
    
         
            +
                        end
         
     | 
| 
      
 310 
     | 
    
         
            +
                      else
         
     | 
| 
      
 311 
     | 
    
         
            +
                        Calculator.stdlib
         
     | 
| 
      
 312 
     | 
    
         
            +
                      end
         
     | 
| 
      
 313 
     | 
    
         
            +
                    else
         
     | 
| 
      
 314 
     | 
    
         
            +
                      raise NotImplementedException, "Only optimized access is supported"
         
     | 
| 
      
 315 
     | 
    
         
            +
                    end
         
     | 
| 
      
 316 
     | 
    
         
            +
                  else
         
     | 
| 
      
 317 
     | 
    
         
            +
                    raise NotImplementedException, "Only require 'stdlib' is supported"
         
     | 
| 
      
 318 
     | 
    
         
            +
                  end
         
     | 
| 
      
 319 
     | 
    
         
            +
                end
         
     | 
| 
      
 320 
     | 
    
         
            +
                
         
     | 
| 
      
 321 
     | 
    
         
            +
                def optimize_stdlib_access?
         
     | 
| 
      
 322 
     | 
    
         
            +
                  true
         
     | 
| 
      
 323 
     | 
    
         
            +
                end
         
     | 
| 
      
 324 
     | 
    
         
            +
                  
         
     | 
| 
      
 325 
     | 
    
         
            +
              end
         
     | 
| 
      
 326 
     | 
    
         
            +
              
         
     | 
| 
      
 327 
     | 
    
         
            +
              
         
     | 
| 
      
 328 
     | 
    
         
            +
              # This module exists only for performance reason.
         
     | 
| 
      
 329 
     | 
    
         
            +
              # Loading the stdlib directly from a ruby object,
         
     | 
| 
      
 330 
     | 
    
         
            +
              # should be much faster than loading it from a file.
         
     | 
| 
      
 331 
     | 
    
         
            +
              
         
     | 
| 
      
 332 
     | 
    
         
            +
              module StdLib
         
     | 
| 
      
 333 
     | 
    
         
            +
                
         
     | 
| 
      
 334 
     | 
    
         
            +
                FOREACH_IN = <<-PROGRAM
         
     | 
| 
      
 335 
     | 
    
         
            +
                  foreach_in = fun(enumerable, body) {
         
     | 
| 
      
 336 
     | 
    
         
            +
                    _foreach_in_(enumerable, body, 0);
         
     | 
| 
      
 337 
     | 
    
         
            +
                  };
         
     | 
| 
      
 338 
     | 
    
         
            +
                  _foreach_in_ = fun(enumerable, body, index) {
         
     | 
| 
      
 339 
     | 
    
         
            +
                    if(index < SIZE(enumerable) - 1)
         
     | 
| 
      
 340 
     | 
    
         
            +
                      body(enumerable[index]);
         
     | 
| 
      
 341 
     | 
    
         
            +
                      _foreach_in_(enumerable, body, index + 1)
         
     | 
| 
      
 342 
     | 
    
         
            +
                    else
         
     | 
| 
      
 343 
     | 
    
         
            +
                      body(enumerable[index])
         
     | 
| 
      
 344 
     | 
    
         
            +
                    end
         
     | 
| 
      
 345 
     | 
    
         
            +
                  };
         
     | 
| 
      
 346 
     | 
    
         
            +
                PROGRAM
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
      
 348 
     | 
    
         
            +
                INJECT = <<-PROGRAM
         
     | 
| 
      
 349 
     | 
    
         
            +
                  inject = fun(memo, enumerable, body) {
         
     | 
| 
      
 350 
     | 
    
         
            +
                    _inject_(memo, enumerable, body, 0);
         
     | 
| 
      
 351 
     | 
    
         
            +
                  };
         
     | 
| 
      
 352 
     | 
    
         
            +
                  _inject_ = fun(memo, enumerable, body, index) {
         
     | 
| 
      
 353 
     | 
    
         
            +
                    if(index < SIZE(enumerable) - 1)
         
     | 
| 
      
 354 
     | 
    
         
            +
                      _inject_(body(memo, enumerable[index]), enumerable, body, index + 1)
         
     | 
| 
      
 355 
     | 
    
         
            +
                    else
         
     | 
| 
      
 356 
     | 
    
         
            +
                      body(memo, enumerable[index])
         
     | 
| 
      
 357 
     | 
    
         
            +
                    end
         
     | 
| 
      
 358 
     | 
    
         
            +
                  };
         
     | 
| 
      
 359 
     | 
    
         
            +
                PROGRAM
         
     | 
| 
      
 360 
     | 
    
         
            +
             
     | 
| 
      
 361 
     | 
    
         
            +
                MAP = <<-PROGRAM
         
     | 
| 
      
 362 
     | 
    
         
            +
                  require 'stdlib/inject';
         
     | 
| 
      
 363 
     | 
    
         
            +
                  map = fun(enumerable, body) {
         
     | 
| 
      
 364 
     | 
    
         
            +
                    b = body; # WORK AROUND a bug in Trxl::Environment
         
     | 
| 
      
 365 
     | 
    
         
            +
                    inject([], enumerable, fun(memo, e) { memo << b(e); });
         
     | 
| 
      
 366 
     | 
    
         
            +
                  };
         
     | 
| 
      
 367 
     | 
    
         
            +
                PROGRAM
         
     | 
| 
      
 368 
     | 
    
         
            +
             
     | 
| 
      
 369 
     | 
    
         
            +
                SELECT = <<-PROGRAM
         
     | 
| 
      
 370 
     | 
    
         
            +
                  require 'stdlib/inject';
         
     | 
| 
      
 371 
     | 
    
         
            +
                  select = fun(enumerable, body) {
         
     | 
| 
      
 372 
     | 
    
         
            +
                    b = body; # WORK AROUND a bug in Trxl::Environment
         
     | 
| 
      
 373 
     | 
    
         
            +
                    inject([], enumerable, fun(selected, value) { 
         
     | 
| 
      
 374 
     | 
    
         
            +
                      if(b(value))
         
     | 
| 
      
 375 
     | 
    
         
            +
                        selected << value
         
     | 
| 
      
 376 
     | 
    
         
            +
                      else
         
     | 
| 
      
 377 
     | 
    
         
            +
                        selected
         
     | 
| 
      
 378 
     | 
    
         
            +
                      end 
         
     | 
| 
      
 379 
     | 
    
         
            +
                    });
         
     | 
| 
      
 380 
     | 
    
         
            +
                  };
         
     | 
| 
      
 381 
     | 
    
         
            +
                PROGRAM
         
     | 
| 
      
 382 
     | 
    
         
            +
                
         
     | 
| 
      
 383 
     | 
    
         
            +
                REJECT = <<-REJECT
         
     | 
| 
      
 384 
     | 
    
         
            +
                  require 'stdlib/inject';
         
     | 
| 
      
 385 
     | 
    
         
            +
                  reject = fun(enumerable, filter) {
         
     | 
| 
      
 386 
     | 
    
         
            +
                    f = filter; # WORKAROUND for a bug in Trxl::Environment
         
     | 
| 
      
 387 
     | 
    
         
            +
                    inject([], enumerable, fun(rejected, value) {
         
     | 
| 
      
 388 
     | 
    
         
            +
                      if(f(value)) 
         
     | 
| 
      
 389 
     | 
    
         
            +
                        rejected
         
     | 
| 
      
 390 
     | 
    
         
            +
                      else
         
     | 
| 
      
 391 
     | 
    
         
            +
                        rejected << value
         
     | 
| 
      
 392 
     | 
    
         
            +
                      end 
         
     | 
| 
      
 393 
     | 
    
         
            +
                    })
         
     | 
| 
      
 394 
     | 
    
         
            +
                  };
         
     | 
| 
      
 395 
     | 
    
         
            +
                REJECT
         
     | 
| 
      
 396 
     | 
    
         
            +
                
         
     | 
| 
      
 397 
     | 
    
         
            +
                IN_GROUPS_OF = <<-IN_GROUPS_OF
         
     | 
| 
      
 398 
     | 
    
         
            +
                  require 'stdlib/foreach_in';
         
     | 
| 
      
 399 
     | 
    
         
            +
                  require 'stdlib/inject';
         
     | 
| 
      
 400 
     | 
    
         
            +
                  in_groups_of = fun(size_of_group, enumerable, group_function) {
         
     | 
| 
      
 401 
     | 
    
         
            +
                    count = 0; groups = []; cur_group = []; 
         
     | 
| 
      
 402 
     | 
    
         
            +
                    foreach_in(enumerable, fun(element) {
         
     | 
| 
      
 403 
     | 
    
         
            +
                      if(count < size_of_group)
         
     | 
| 
      
 404 
     | 
    
         
            +
                        cur_group << element;
         
     | 
| 
      
 405 
     | 
    
         
            +
                        count = count + 1
         
     | 
| 
      
 406 
     | 
    
         
            +
                      end;
         
     | 
| 
      
 407 
     | 
    
         
            +
                      if(count == size_of_group)
         
     | 
| 
      
 408 
     | 
    
         
            +
                        groups << cur_group;
         
     | 
| 
      
 409 
     | 
    
         
            +
                        cur_group = [];
         
     | 
| 
      
 410 
     | 
    
         
            +
                        count = 0
         
     | 
| 
      
 411 
     | 
    
         
            +
                      end
         
     | 
| 
      
 412 
     | 
    
         
            +
                    });
         
     | 
| 
      
 413 
     | 
    
         
            +
                    group_count = 0;
         
     | 
| 
      
 414 
     | 
    
         
            +
                    inject([], groups, fun(memo, group) {
         
     | 
| 
      
 415 
     | 
    
         
            +
                      group_count = group_count + 1;
         
     | 
| 
      
 416 
     | 
    
         
            +
                      memo << group_function(group, group_count);
         
     | 
| 
      
 417 
     | 
    
         
            +
                      memo
         
     | 
| 
      
 418 
     | 
    
         
            +
                    });
         
     | 
| 
      
 419 
     | 
    
         
            +
                  };
         
     | 
| 
      
 420 
     | 
    
         
            +
                IN_GROUPS_OF
         
     | 
| 
      
 421 
     | 
    
         
            +
                
         
     | 
| 
      
 422 
     | 
    
         
            +
                SUM_OF_TYPE = <<-SUM_OF_TYPE
         
     | 
| 
      
 423 
     | 
    
         
            +
                  sum_of_type = fun(type, all_types, all_values) {
         
     | 
| 
      
 424 
     | 
    
         
            +
                    SUM(VALUES_OF_TYPE(type, all_types, all_values));
         
     | 
| 
      
 425 
     | 
    
         
            +
                  };
         
     | 
| 
      
 426 
     | 
    
         
            +
                SUM_OF_TYPE
         
     | 
| 
      
 427 
     | 
    
         
            +
             
     | 
| 
      
 428 
     | 
    
         
            +
                AVG_SUM_OF_TYPE = <<-AVG_SUM_OF_TYPE
         
     | 
| 
      
 429 
     | 
    
         
            +
                  avg_sum_of_type = fun(type, all_types, all_values) {
         
     | 
| 
      
 430 
     | 
    
         
            +
                    AVG_SUM(VALUES_OF_TYPE(type, all_types, all_values));
         
     | 
| 
      
 431 
     | 
    
         
            +
                  };
         
     | 
| 
      
 432 
     | 
    
         
            +
                AVG_SUM_OF_TYPE
         
     | 
| 
      
 433 
     | 
    
         
            +
             
     | 
| 
      
 434 
     | 
    
         
            +
                AVG_RANGE_SUM_OF_TYPE = <<-AVG_RANGE_SUM_OF_TYPE
         
     | 
| 
      
 435 
     | 
    
         
            +
                  require 'stdlib/inject';
         
     | 
| 
      
 436 
     | 
    
         
            +
                  require 'stdlib/avg_sum_of_type';
         
     | 
| 
      
 437 
     | 
    
         
            +
                  avg_range_sum_of_type = fun(type, all_types, variable_range) {
         
     | 
| 
      
 438 
     | 
    
         
            +
                    inject(0, variable_range, fun(sum, variable) { 
         
     | 
| 
      
 439 
     | 
    
         
            +
                      sum + avg_sum_of_type(type, all_types, ENV[variable]) 
         
     | 
| 
      
 440 
     | 
    
         
            +
                    });
         
     | 
| 
      
 441 
     | 
    
         
            +
                  };
         
     | 
| 
      
 442 
     | 
    
         
            +
                AVG_RANGE_SUM_OF_TYPE
         
     | 
| 
      
 443 
     | 
    
         
            +
                
         
     | 
| 
      
 444 
     | 
    
         
            +
                TOTAL_RANGE_SUM_OF_TYPE = <<-TOTAL_RANGE_SUM_OF_TYPE
         
     | 
| 
      
 445 
     | 
    
         
            +
                  require 'stdlib/inject';
         
     | 
| 
      
 446 
     | 
    
         
            +
                  require 'stdlib/sum_of_type';
         
     | 
| 
      
 447 
     | 
    
         
            +
                  total_range_sum_of_type = fun(type, all_types, variable_range) {
         
     | 
| 
      
 448 
     | 
    
         
            +
                    inject(0, variable_range, fun(sum, variable) { 
         
     | 
| 
      
 449 
     | 
    
         
            +
                      sum + sum_of_type(type, all_types, ENV[variable]) 
         
     | 
| 
      
 450 
     | 
    
         
            +
                    });
         
     | 
| 
      
 451 
     | 
    
         
            +
                  };
         
     | 
| 
      
 452 
     | 
    
         
            +
                TOTAL_RANGE_SUM_OF_TYPE
         
     | 
| 
      
 453 
     | 
    
         
            +
             
     | 
| 
      
 454 
     | 
    
         
            +
                YEAR_FROM_DATE = <<-YEAR_FROM_DATE
         
     | 
| 
      
 455 
     | 
    
         
            +
                  year_from_date = fun(date) {
         
     | 
| 
      
 456 
     | 
    
         
            +
                    date = SPLIT(date, '/');
         
     | 
| 
      
 457 
     | 
    
         
            +
                    TO_INT(date[1]);
         
     | 
| 
      
 458 
     | 
    
         
            +
                  };
         
     | 
| 
      
 459 
     | 
    
         
            +
                YEAR_FROM_DATE
         
     | 
| 
      
 460 
     | 
    
         
            +
             
     | 
| 
      
 461 
     | 
    
         
            +
                MONTH_FROM_DATE = <<-MONTH_FROM_DATE
         
     | 
| 
      
 462 
     | 
    
         
            +
                  month_from_date = fun(date) {
         
     | 
| 
      
 463 
     | 
    
         
            +
                    date = SPLIT(date, '/');
         
     | 
| 
      
 464 
     | 
    
         
            +
                    TO_INT(date[0]);
         
     | 
| 
      
 465 
     | 
    
         
            +
                  };
         
     | 
| 
      
 466 
     | 
    
         
            +
                MONTH_FROM_DATE
         
     | 
| 
      
 467 
     | 
    
         
            +
             
     | 
| 
      
 468 
     | 
    
         
            +
                DATES = <<-DATES
         
     | 
| 
      
 469 
     | 
    
         
            +
                  require 'stdlib/month_from_date';
         
     | 
| 
      
 470 
     | 
    
         
            +
                  require 'stdlib/year_from_date';
         
     | 
| 
      
 471 
     | 
    
         
            +
                DATES
         
     | 
| 
      
 472 
     | 
    
         
            +
                
         
     | 
| 
      
 473 
     | 
    
         
            +
                RATIO = <<-RATIO
         
     | 
| 
      
 474 
     | 
    
         
            +
                  require 'stdlib/foreach_in';
         
     | 
| 
      
 475 
     | 
    
         
            +
                  ratio = fun(enumerable, true_condition, base_condition) {
         
     | 
| 
      
 476 
     | 
    
         
            +
                    base = 0;
         
     | 
| 
      
 477 
     | 
    
         
            +
                    positives = 0;
         
     | 
| 
      
 478 
     | 
    
         
            +
                    foreach_in(enumerable, fun(val) {
         
     | 
| 
      
 479 
     | 
    
         
            +
                      if(ENV[val] != base_condition)
         
     | 
| 
      
 480 
     | 
    
         
            +
                        base = base + 1
         
     | 
| 
      
 481 
     | 
    
         
            +
                      end;
         
     | 
| 
      
 482 
     | 
    
         
            +
                      if(ENV[val] == true_condition)
         
     | 
| 
      
 483 
     | 
    
         
            +
                        positives = positives + 1
         
     | 
| 
      
 484 
     | 
    
         
            +
                      end;
         
     | 
| 
      
 485 
     | 
    
         
            +
                    });
         
     | 
| 
      
 486 
     | 
    
         
            +
                    if(base > 0)
         
     | 
| 
      
 487 
     | 
    
         
            +
                      ROUND((ROUND(positives, 1) / base) * 100, 2)
         
     | 
| 
      
 488 
     | 
    
         
            +
                    else
         
     | 
| 
      
 489 
     | 
    
         
            +
                      NULL
         
     | 
| 
      
 490 
     | 
    
         
            +
                    end
         
     | 
| 
      
 491 
     | 
    
         
            +
                  };
         
     | 
| 
      
 492 
     | 
    
         
            +
                RATIO
         
     | 
| 
      
 493 
     | 
    
         
            +
             
     | 
| 
      
 494 
     | 
    
         
            +
              end
         
     | 
| 
      
 495 
     | 
    
         
            +
              
         
     | 
| 
      
 496 
     | 
    
         
            +
              
         
     | 
| 
      
 497 
     | 
    
         
            +
              class Calculator
         
     | 
| 
      
 498 
     | 
    
         
            +
                
         
     | 
| 
      
 499 
     | 
    
         
            +
                extend StdLib # optimized for performance
         
     | 
| 
      
 500 
     | 
    
         
            +
                
         
     | 
| 
      
 501 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 502 
     | 
    
         
            +
                  
         
     | 
| 
      
 503 
     | 
    
         
            +
                  def stdlib(function = nil)
         
     | 
| 
      
 504 
     | 
    
         
            +
                    if function
         
     | 
| 
      
 505 
     | 
    
         
            +
                      Kernel.eval("Trxl::StdLib::#{function.to_s.upcase}").strip
         
     | 
| 
      
 506 
     | 
    
         
            +
                    else
         
     | 
| 
      
 507 
     | 
    
         
            +
                      Trxl::StdLib.constants.inject('') do |lib, const|
         
     | 
| 
      
 508 
     | 
    
         
            +
                        lib << Kernel.eval("Trxl::StdLib::#{const}")
         
     | 
| 
      
 509 
     | 
    
         
            +
                      end.strip
         
     | 
| 
      
 510 
     | 
    
         
            +
                    end
         
     | 
| 
      
 511 
     | 
    
         
            +
                  end
         
     | 
| 
      
 512 
     | 
    
         
            +
                  
         
     | 
| 
      
 513 
     | 
    
         
            +
                end
         
     | 
| 
      
 514 
     | 
    
         
            +
             
     | 
| 
      
 515 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 516 
     | 
    
         
            +
                  @parser = TrxlParser.new
         
     | 
| 
      
 517 
     | 
    
         
            +
                end
         
     | 
| 
      
 518 
     | 
    
         
            +
             
     | 
| 
      
 519 
     | 
    
         
            +
                # may raise
         
     | 
| 
      
 520 
     | 
    
         
            +
                # overwrite treetop to provide more precise exceptions
         
     | 
| 
      
 521 
     | 
    
         
            +
                def parse(code, verbose = true)
         
     | 
| 
      
 522 
     | 
    
         
            +
                  if ast = @parser.parse(code)
         
     | 
| 
      
 523 
     | 
    
         
            +
                    ast
         
     | 
| 
      
 524 
     | 
    
         
            +
                  else
         
     | 
| 
      
 525 
     | 
    
         
            +
                    failure_idx = @parser.failure_index
         
     | 
| 
      
 526 
     | 
    
         
            +
                    
         
     | 
| 
      
 527 
     | 
    
         
            +
                    # extract code snippet where parse error happened
         
     | 
| 
      
 528 
     | 
    
         
            +
                    start = ((idx = failure_idx - 12) < 0 ? 0 : idx)
         
     | 
| 
      
 529 
     | 
    
         
            +
                    stop  = ((idx = failure_idx + 12) > code.size ? code.size : idx)
         
     | 
| 
      
 530 
     | 
    
         
            +
                    local_code = code.slice(start..stop).to_s.gsub(/\n|\r/, "")
         
     | 
| 
      
 531 
     | 
    
         
            +
                    
         
     | 
| 
      
 532 
     | 
    
         
            +
                    msg =  "Parse Error at index #{failure_idx} (showing excerpt):\n"
         
     | 
| 
      
 533 
     | 
    
         
            +
                    msg << "... #{local_code} ...\n"
         
     | 
| 
      
 534 
     | 
    
         
            +
                    
         
     | 
| 
      
 535 
     | 
    
         
            +
                    # mark the exact offset where the parse error happened
         
     | 
| 
      
 536 
     | 
    
         
            +
                    offset = (start == 0) ? failure_idx + 4 : 16
         
     | 
| 
      
 537 
     | 
    
         
            +
                    offset.times { msg << ' '}; msg << "^\n"
         
     | 
| 
      
 538 
     | 
    
         
            +
                    
         
     | 
| 
      
 539 
     | 
    
         
            +
                    if verbose
         
     | 
| 
      
 540 
     | 
    
         
            +
                      # show the originial trxl program
         
     | 
| 
      
 541 
     | 
    
         
            +
                      msg << "Original Code:\n#{code}\n\n"
         
     | 
| 
      
 542 
     | 
    
         
            +
                      # add detailed treetop parser error messages
         
     | 
| 
      
 543 
     | 
    
         
            +
                      msg << @parser.failure_reason
         
     | 
| 
      
 544 
     | 
    
         
            +
                    end
         
     | 
| 
      
 545 
     | 
    
         
            +
                    raise(Trxl::FatalParseError, msg)
         
     | 
| 
      
 546 
     | 
    
         
            +
                  end
         
     | 
| 
      
 547 
     | 
    
         
            +
                end
         
     | 
| 
      
 548 
     | 
    
         
            +
             
     | 
| 
      
 549 
     | 
    
         
            +
                # may raise
         
     | 
| 
      
 550 
     | 
    
         
            +
                # eval an expression in calculations.treetop grammar
         
     | 
| 
      
 551 
     | 
    
         
            +
                # eval an already parsed Treetop::Runtime::SyntaxNode
         
     | 
| 
      
 552 
     | 
    
         
            +
                def eval(expression, env = Environment.new, verbose = true, interpreter_mode = false)
         
     | 
| 
      
 553 
     | 
    
         
            +
                  if expression.is_a?(Treetop::Runtime::SyntaxNode)
         
     | 
| 
      
 554 
     | 
    
         
            +
                    interpreter_mode ? [ expression.eval(env), env ] : expression.eval(env)
         
     | 
| 
      
 555 
     | 
    
         
            +
                  else
         
     | 
| 
      
 556 
     | 
    
         
            +
                    ast = parse(expression, verbose)
         
     | 
| 
      
 557 
     | 
    
         
            +
                    interpreter_mode ? [ ast.eval(env), env ] : ast.eval(env)
         
     | 
| 
      
 558 
     | 
    
         
            +
                  end
         
     | 
| 
      
 559 
     | 
    
         
            +
                end
         
     | 
| 
      
 560 
     | 
    
         
            +
             
     | 
| 
      
 561 
     | 
    
         
            +
              end
         
     | 
| 
      
 562 
     | 
    
         
            +
              
         
     | 
| 
      
 563 
     | 
    
         
            +
              class Interpreter
         
     | 
| 
      
 564 
     | 
    
         
            +
                
         
     | 
| 
      
 565 
     | 
    
         
            +
                attr_accessor :parser, :program, :env
         
     | 
| 
      
 566 
     | 
    
         
            +
                
         
     | 
| 
      
 567 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 568 
     | 
    
         
            +
                  @parser = Calculator.new
         
     | 
| 
      
 569 
     | 
    
         
            +
                  @program = []
         
     | 
| 
      
 570 
     | 
    
         
            +
                  @env = env
         
     | 
| 
      
 571 
     | 
    
         
            +
                end
         
     | 
| 
      
 572 
     | 
    
         
            +
                
         
     | 
| 
      
 573 
     | 
    
         
            +
                def stash(loc)
         
     | 
| 
      
 574 
     | 
    
         
            +
                  @program << loc
         
     | 
| 
      
 575 
     | 
    
         
            +
                end
         
     | 
| 
      
 576 
     | 
    
         
            +
                
         
     | 
| 
      
 577 
     | 
    
         
            +
                def eval(env = [])
         
     | 
| 
      
 578 
     | 
    
         
            +
                  @parser.eval(@program.join(' '), env)
         
     | 
| 
      
 579 
     | 
    
         
            +
                end
         
     | 
| 
      
 580 
     | 
    
         
            +
                
         
     | 
| 
      
 581 
     | 
    
         
            +
              end
         
     | 
| 
      
 582 
     | 
    
         
            +
              
         
     | 
| 
      
 583 
     | 
    
         
            +
            end
         
     | 
| 
      
 584 
     | 
    
         
            +
             
     | 
| 
      
 585 
     | 
    
         
            +
             
     |