skeem 0.0.14 → 0.0.15
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +15 -1
- data/lib/skeem/interpreter.rb +16 -0
- data/lib/skeem/s_expr_builder.rb +0 -2
- data/lib/skeem/s_expr_nodes.rb +8 -17
- data/lib/skeem/standard/base.skm +25 -0
- data/lib/skeem/version.rb +1 -1
- data/skeem.gemspec +1 -0
- data/spec/skeem/interpreter_spec.rb +90 -13
- metadata +3 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 17793fa7c6e636874b0d7fe8515d745b7ff664af
         | 
| 4 | 
            +
              data.tar.gz: f24f83ad056e1af1ecac866e2daa649c94e544e6
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 64d9feba80f8ac945161c326a8783cdd34babf4f46bbec94020192ad7643a408be059c72e922bf452387dff253708d2b855d7adbac93b9bb9fff0cf4f354bbce
         | 
| 7 | 
            +
              data.tar.gz: 00f745fc5abeaa2f1f6d83007b21bc0cb7a4fbc3974d79f71be89c19324857a543339328d406a04ca5dd130e36c789c163e3b982c3be87b879b1978fbb277492
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,17 @@ | |
| 1 | 
            +
            ## [0.0.15] - 2018-09-30
         | 
| 2 | 
            +
            Recursive functions are now supported.  
         | 
| 3 | 
            +
            Interpreter pre-loads a Scheme file with standard procedures (zero?, positive?, negative?, abs)
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ### Added
         | 
| 6 | 
            +
            - File `base.skm` with standard Scheme procedures `zero?`, `positive?`, `negative?`, `abs`
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            ### Changed
         | 
| 9 | 
            +
            - Class `Interpreter#initialize` now execute a Scheme file containing a number of standard procedures.
         | 
| 10 | 
            +
            - File `README.md` Added third demo snippet showing example of recursive lambda function.
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ### Fixed
         | 
| 13 | 
            +
            - Method `SkmLambda#bind_locals` now execute any procedure call in argument list before executing the lambda itself.
         | 
| 14 | 
            +
             | 
| 1 15 | 
             
            ## [0.0.14] - 2018-09-23
         | 
| 2 16 | 
             
            Added `lambda` (anonymous function). This is an initial implementation that doesn't support recursion yet.
         | 
| 3 17 |  | 
    
        data/README.md
    CHANGED
    
    | @@ -55,7 +55,6 @@ At this stage, the gem consists of a bare-bones interpreter. | |
| 55 55 | 
             
            ```
         | 
| 56 56 |  | 
| 57 57 | 
             
            ### Example 2 (Defining a function)
         | 
| 58 | 
            -
            Remark: Skeem 0.0.14 doesn't support recursive functions yet.
         | 
| 59 58 |  | 
| 60 59 | 
             
            ```ruby
         | 
| 61 60 | 
             
              require 'skeem'
         | 
| @@ -79,6 +78,21 @@ Remark: Skeem 0.0.14 doesn't support recursive functions yet. | |
| 79 78 | 
             
              result = schemer.run(scheme_code)
         | 
| 80 79 | 
             
              puts result.value # => 3
         | 
| 81 80 | 
             
            ```
         | 
| 81 | 
            +
            ### Example 3 (Defining a recursive function)
         | 
| 82 | 
            +
            ```ruby
         | 
| 83 | 
            +
              require 'skeem'
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              schemer = Skeem::Interpreter.new
         | 
| 86 | 
            +
              scheme_code = <<-SKEEM
         | 
| 87 | 
            +
                ; Compute the factorial of 100
         | 
| 88 | 
            +
                (define fact (lambda (n)
         | 
| 89 | 
            +
                  (if (<= n 1) 1 (* n (fact (- n 1))))))
         | 
| 90 | 
            +
                (fact 100)
         | 
| 91 | 
            +
              SKEEM
         | 
| 92 | 
            +
             | 
| 93 | 
            +
              result = schemer.run(scheme_code)
         | 
| 94 | 
            +
              puts result.value # => 9332621544394415268169923885626670049071596826438162146859296389521759999322991560894146397615651828625369792082722375825118521091686400000000000000000000000 
         | 
| 95 | 
            +
            ```
         | 
| 82 96 |  | 
| 83 97 | 
             
            Roadmap:
         | 
| 84 98 | 
             
            - Extend language support
         | 
    
        data/lib/skeem/interpreter.rb
    CHANGED
    
    | @@ -12,6 +12,7 @@ module Skeem | |
| 12 12 | 
             
                def initialize()
         | 
| 13 13 | 
             
                  @runtime = Runtime.new(Environment.new)
         | 
| 14 14 | 
             
                  add_primitives(runtime)
         | 
| 15 | 
            +
                  add_standard(runtime)
         | 
| 15 16 | 
             
                end
         | 
| 16 17 |  | 
| 17 18 | 
             
                def run(source)
         | 
| @@ -19,5 +20,20 @@ module Skeem | |
| 19 20 | 
             
                  @ptree = parser.parse(source)
         | 
| 20 21 | 
             
                  return @ptree.root.evaluate(runtime)
         | 
| 21 22 | 
             
                end
         | 
| 23 | 
            +
                
         | 
| 24 | 
            +
                private
         | 
| 25 | 
            +
                
         | 
| 26 | 
            +
                def add_standard(aRuntime)
         | 
| 27 | 
            +
                  std_pathname = File.dirname(__FILE__) + '/standard/base.skm'
         | 
| 28 | 
            +
                  load_lib(std_pathname)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
                
         | 
| 31 | 
            +
                def load_lib(aPathname)
         | 
| 32 | 
            +
                  lib_source = nil
         | 
| 33 | 
            +
                  File.open(aPathname, 'r') do |lib| 
         | 
| 34 | 
            +
                    lib_source = lib.read 
         | 
| 35 | 
            +
                    run(lib_source)
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 22 38 | 
             
              end # class
         | 
| 23 39 | 
             
            end # module
         | 
    
        data/lib/skeem/s_expr_builder.rb
    CHANGED
    
    | @@ -85,8 +85,6 @@ module Skeem | |
| 85 85 | 
             
                # rule('lambda_expression' => 'LPAREN LAMBDA formals body RPAREN').as 'lambda_expression'
         | 
| 86 86 | 
             
                def reduce_lambda_expression(_production, _range, _tokens, theChildren)
         | 
| 87 87 | 
             
                  lmbd = SkmLambda.new(_range, theChildren[2], theChildren[3])
         | 
| 88 | 
            -
                  # puts lmbd.inspect
         | 
| 89 | 
            -
                  lmbd
         | 
| 90 88 | 
             
                end
         | 
| 91 89 |  | 
| 92 90 | 
             
                # rule('formals' => 'LPAREN identifier_star RPAREN').as 'identifiers_as_formals'
         | 
    
        data/lib/skeem/s_expr_nodes.rb
    CHANGED
    
    | @@ -325,7 +325,11 @@ module Skeem | |
| 325 325 | 
             
                    raise err, err_msg
         | 
| 326 326 | 
             
                  end
         | 
| 327 327 | 
             
                  procedure = aRuntime.environment.fetch(var_key.value)
         | 
| 328 | 
            +
                  # puts "## CALL(#{var_key.value}) ###################"
         | 
| 329 | 
            +
                  # puts operands.inspect
         | 
| 328 330 | 
             
                  result = procedure.call(aRuntime, self)
         | 
| 331 | 
            +
                  # puts "## RETURN #{result.inspect}"
         | 
| 332 | 
            +
                  result
         | 
| 329 333 | 
             
                end
         | 
| 330 334 |  | 
| 331 335 | 
             
                def inspect
         | 
| @@ -367,21 +371,6 @@ module Skeem | |
| 367 371 | 
             
                  result
         | 
| 368 372 | 
             
                end
         | 
| 369 373 | 
             
              end # class
         | 
| 370 | 
            -
              
         | 
| 371 | 
            -
            =begin
         | 
| 372 | 
            -
            <Skeem::SkmLambda: 
         | 
| 373 | 
            -
              @formals [<Skeem::SkmIdentifier: x>]
         | 
| 374 | 
            -
              @definitions nil
         | 
| 375 | 
            -
              @sequence <Skeem::SkmList: 
         | 
| 376 | 
            -
                <Skeem::SkmCondition: 
         | 
| 377 | 
            -
                  @test <Skeem::ProcedureCall: <Skeem::SkmIdentifier: <>, 
         | 
| 378 | 
            -
                    <Skeem::SkmList: <Skeem::SkmVariableReference: <Skeem::SkmIdentifier: x>>, 
         | 
| 379 | 
            -
                    <Skeem::SkmInteger: 0>>>, 
         | 
| 380 | 
            -
                  @consequent <Skeem::ProcedureCall: 
         | 
| 381 | 
            -
                    <Skeem::SkmIdentifier: ->, 
         | 
| 382 | 
            -
                    <Skeem::SkmList: <Skeem::SkmVariableReference: <Skeem::SkmIdentifier: x>>>>,
         | 
| 383 | 
            -
                  @alternate <Skeem::SkmVariableReference: <Skeem::SkmIdentifier: x>>>>>
         | 
| 384 | 
            -
            =end
         | 
| 385 374 |  | 
| 386 375 | 
             
              class SkmLambda < SkmElement
         | 
| 387 376 | 
             
                # @!attribute [r] formals
         | 
| @@ -427,12 +416,14 @@ module Skeem | |
| 427 416 | 
             
                  formals.each_with_index do |arg_name, index|
         | 
| 428 417 | 
             
                    arg = arguments[index]
         | 
| 429 418 | 
             
                    if arg.nil?
         | 
| 430 | 
            -
                      p aProcedureCall.operands.members
         | 
| 431 419 | 
             
                      raise StandardError, "Unbound variable: '#{arg_name.value}'"
         | 
| 432 420 | 
             
                    end
         | 
| 433 | 
            -
             | 
| 421 | 
            +
                    
         | 
| 422 | 
            +
                    # IMPORTANT: execute procedure call in argument list now
         | 
| 423 | 
            +
                    arg = arg.evaluate(aRuntime) if arg.kind_of?(ProcedureCall)
         | 
| 434 424 | 
             
                    a_def = SkmDefinition.new(position, arg_name, arg)
         | 
| 435 425 | 
             
                    a_def.evaluate(aRuntime)
         | 
| 426 | 
            +
                    # puts "LOCAL #{a_def.inspect}"
         | 
| 436 427 | 
             
                  end
         | 
| 437 428 | 
             
                end
         | 
| 438 429 |  | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            ; Standard R7RS procedures from section 6.2.6
         | 
| 2 | 
            +
            (define zero? 
         | 
| 3 | 
            +
              (lambda (z)
         | 
| 4 | 
            +
                (if (= z 0)
         | 
| 5 | 
            +
                  #t
         | 
| 6 | 
            +
                  #f)))
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            ; Return true if x greater or equal to zero; false otherwise
         | 
| 9 | 
            +
            (define positive? 
         | 
| 10 | 
            +
              (lambda (x)
         | 
| 11 | 
            +
                (if (>= x 0)
         | 
| 12 | 
            +
                  #t
         | 
| 13 | 
            +
                  #f)))
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            (define negative? 
         | 
| 16 | 
            +
              (lambda (x)
         | 
| 17 | 
            +
                (if (< x 0)
         | 
| 18 | 
            +
                  #t
         | 
| 19 | 
            +
                  #f)))
         | 
| 20 | 
            +
                  
         | 
| 21 | 
            +
            (define abs 
         | 
| 22 | 
            +
              (lambda (x)
         | 
| 23 | 
            +
                (if (>= x 0)
         | 
| 24 | 
            +
                  x
         | 
| 25 | 
            +
                  (- x))))
         | 
    
        data/lib/skeem/version.rb
    CHANGED
    
    
    
        data/skeem.gemspec
    CHANGED
    
    
| @@ -8,8 +8,8 @@ module Skeem | |
| 8 8 | 
             
                    expect { Interpreter.new() }.not_to raise_error
         | 
| 9 9 | 
             
                  end
         | 
| 10 10 |  | 
| 11 | 
            -
                  it 'should  | 
| 12 | 
            -
                    expect(subject.parser). | 
| 11 | 
            +
                  it 'should have a parser' do
         | 
| 12 | 
            +
                    expect(subject.parser).not_to be_nil
         | 
| 13 13 | 
             
                  end
         | 
| 14 14 |  | 
| 15 15 | 
             
                  it 'should have a runtime object' do
         | 
| @@ -154,17 +154,17 @@ SKEEM | |
| 154 154 | 
             
                    result = subject.run('(min 2 2)')
         | 
| 155 155 | 
             
                    expect(result.value).to eq(2)
         | 
| 156 156 | 
             
                  end      
         | 
| 157 | 
            -
             | 
| 158 | 
            -
                   | 
| 159 | 
            -
                     | 
| 160 | 
            -
               | 
| 161 | 
            -
               | 
| 162 | 
            -
                 | 
| 163 | 
            -
               | 
| 164 | 
            -
             | 
| 165 | 
            -
                     | 
| 166 | 
            -
                     | 
| 167 | 
            -
                   | 
| 157 | 
            +
                 
         | 
| 158 | 
            +
                  it 'should implement recursive functions' do
         | 
| 159 | 
            +
                    source = <<-SKEEM
         | 
| 160 | 
            +
              ; Example from R7RS section 4.1.5
         | 
| 161 | 
            +
              (define fact (lambda (n) 
         | 
| 162 | 
            +
                (if (<= n 1) 1 (* n (fact (- n 1))))))
         | 
| 163 | 
            +
              (fact 10)
         | 
| 164 | 
            +
            SKEEM
         | 
| 165 | 
            +
                    result = subject.run(source)
         | 
| 166 | 
            +
                    expect(result.value).to eq(3628800)    
         | 
| 167 | 
            +
                  end
         | 
| 168 168 | 
             
                end # context
         | 
| 169 169 |  | 
| 170 170 | 
             
                context 'Built-in primitive procedures' do
         | 
| @@ -377,5 +377,82 @@ SKEEM | |
| 377 377 | 
             
                    end
         | 
| 378 378 | 
             
                  end
         | 
| 379 379 | 
             
                end # context
         | 
| 380 | 
            +
                
         | 
| 381 | 
            +
                context 'Built-in standard procedures' do
         | 
| 382 | 
            +
                  it 'should implement the zero? predicate' do
         | 
| 383 | 
            +
                    checks = [
         | 
| 384 | 
            +
                      ['(zero? 3.1)', false],
         | 
| 385 | 
            +
                      ['(zero? -3.1)', false],       
         | 
| 386 | 
            +
                      ['(zero? 0)', true],
         | 
| 387 | 
            +
                      ['(zero? 0.0)', true],
         | 
| 388 | 
            +
                      ['(zero? 3)', false],
         | 
| 389 | 
            +
                      ['(zero? -3)', false]
         | 
| 390 | 
            +
                    ]
         | 
| 391 | 
            +
                    checks.each do |(skeem_expr, expectation)|
         | 
| 392 | 
            +
                      result = subject.run(skeem_expr)
         | 
| 393 | 
            +
                      expect(result.value).to eq(expectation)
         | 
| 394 | 
            +
                    end
         | 
| 395 | 
            +
                  end
         | 
| 396 | 
            +
             | 
| 397 | 
            +
                  it 'should implement the positive? predicate' do      
         | 
| 398 | 
            +
                    checks = [
         | 
| 399 | 
            +
                      ['(positive? 3.1)', true],
         | 
| 400 | 
            +
                      ['(positive? -3.1)', false],       
         | 
| 401 | 
            +
                      ['(positive? 0)', true],
         | 
| 402 | 
            +
                      ['(positive? 0.0)', true],
         | 
| 403 | 
            +
                      ['(positive? 3)', true],
         | 
| 404 | 
            +
                      ['(positive? -3)', false]
         | 
| 405 | 
            +
                    ]
         | 
| 406 | 
            +
                    checks.each do |(skeem_expr, expectation)|
         | 
| 407 | 
            +
                      result = subject.run(skeem_expr)
         | 
| 408 | 
            +
                      expect(result.value).to eq(expectation)
         | 
| 409 | 
            +
                    end
         | 
| 410 | 
            +
                  end
         | 
| 411 | 
            +
             | 
| 412 | 
            +
                  it 'should implement the positive? predicate' do      
         | 
| 413 | 
            +
                    checks = [
         | 
| 414 | 
            +
                      ['(positive? 3.1)', true],
         | 
| 415 | 
            +
                      ['(positive? -3.1)', false],       
         | 
| 416 | 
            +
                      ['(positive? 0)', true],
         | 
| 417 | 
            +
                      ['(positive? 0.0)', true],
         | 
| 418 | 
            +
                      ['(positive? 3)', true],
         | 
| 419 | 
            +
                      ['(positive? -3)', false]
         | 
| 420 | 
            +
                    ]
         | 
| 421 | 
            +
                    checks.each do |(skeem_expr, expectation)|
         | 
| 422 | 
            +
                      result = subject.run(skeem_expr)
         | 
| 423 | 
            +
                      expect(result.value).to eq(expectation)
         | 
| 424 | 
            +
                    end
         | 
| 425 | 
            +
                  end
         | 
| 426 | 
            +
             | 
| 427 | 
            +
                  it 'should implement the negative? predicate' do      
         | 
| 428 | 
            +
                    checks = [
         | 
| 429 | 
            +
                      ['(negative? 3.1)', false],
         | 
| 430 | 
            +
                      ['(negative? -3.1)', true],       
         | 
| 431 | 
            +
                      ['(negative? 0)', false],
         | 
| 432 | 
            +
                      ['(negative? 0.0)', false],
         | 
| 433 | 
            +
                      ['(negative? 3)', false],
         | 
| 434 | 
            +
                      ['(negative? -3)', true]
         | 
| 435 | 
            +
                    ]
         | 
| 436 | 
            +
                    checks.each do |(skeem_expr, expectation)|
         | 
| 437 | 
            +
                      result = subject.run(skeem_expr)
         | 
| 438 | 
            +
                      expect(result.value).to eq(expectation)
         | 
| 439 | 
            +
                    end
         | 
| 440 | 
            +
                  end
         | 
| 441 | 
            +
             | 
| 442 | 
            +
                  it 'should implement the abs function' do      
         | 
| 443 | 
            +
                    checks = [
         | 
| 444 | 
            +
                      ['(abs 3.1)', 3.1],
         | 
| 445 | 
            +
                      ['(abs -3.1)', 3.1],       
         | 
| 446 | 
            +
                      ['(abs 0)', 0],
         | 
| 447 | 
            +
                      ['(abs 0.0)', 0],
         | 
| 448 | 
            +
                      ['(abs 3)', 3],
         | 
| 449 | 
            +
                      ['(abs -7)', 7]
         | 
| 450 | 
            +
                    ]
         | 
| 451 | 
            +
                    checks.each do |(skeem_expr, expectation)|
         | 
| 452 | 
            +
                      result = subject.run(skeem_expr)
         | 
| 453 | 
            +
                      expect(result.value).to eq(expectation)
         | 
| 454 | 
            +
                    end
         | 
| 455 | 
            +
                  end       
         | 
| 456 | 
            +
                end # context
         | 
| 380 457 | 
             
              end # describe
         | 
| 381 458 | 
             
            end # module
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: skeem
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.15
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Dimitri Geshef
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2018-09- | 
| 11 | 
            +
            date: 2018-09-30 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rley
         | 
| @@ -95,6 +95,7 @@ files: | |
| 95 95 | 
             
            - lib/skeem/runtime.rb
         | 
| 96 96 | 
             
            - lib/skeem/s_expr_builder.rb
         | 
| 97 97 | 
             
            - lib/skeem/s_expr_nodes.rb
         | 
| 98 | 
            +
            - lib/skeem/standard/base.skm
         | 
| 98 99 | 
             
            - lib/skeem/stoken.rb
         | 
| 99 100 | 
             
            - lib/skeem/tokenizer.rb
         | 
| 100 101 | 
             
            - lib/skeem/version.rb
         |