RSpec.describe AST::FunctionCall do it 'evaluates built-in functions' do expect { AST::FunctionCall.new( AST::Identifier.new('print'), [AST::String.new('hello world')] ).execute(Environment.new) }.to output("hello world\n").to_stdout end it 'evaluates user-defined functions' do env = Environment.new AST::FunctionDefinition.new( AST::Identifier.new('add_one'), [AST::Identifier.new('n')], AST::Block.new([ AST::Binary.new( AST::Operators::ADD, AST::Identifier.new('n'), AST::Number.new(1.0) ) ]) ).execute(env) expect( AST::FunctionCall.new( AST::Identifier.new('add_one'), [AST::Number.new(5.0)] ).execute(env) ).to eq(6.0) end # This corresponds to the program # function factorial(n) { # if n == 0 { # 1; # } else { # n * factorial(n - 1); # } # } # factorial(5); it 'evaluates recursive functions' do env = Environment.new AST::FunctionDefinition.new( AST::Identifier.new('factorial'), [AST::Identifier.new('n')], AST::Block.new([ AST::Conditional.new( [ AST::Branch.new( AST::Binary.new( AST::Operators::DOUBLE_EQUALS, AST::Identifier.new('n'), AST::Number.new(0.0), ), AST::Block.new([ AST::Number.new(1.0), ]) ), AST::Branch.new( AST::Boolean.new(true), AST::Block.new([ AST::Binary.new( AST::Operators::MULTIPLY, AST::Identifier.new('n'), AST::FunctionCall.new( AST::Identifier.new('factorial'), [ AST::Binary.new( AST::Operators::SUBTRACT, AST::Identifier.new('n'), AST::Number.new(1.0), ) ] ) ) ]) ), ] ) ]) ).execute(env) expect( AST::FunctionCall.new( AST::Identifier.new('factorial'), [AST::Number.new(5.0)] ).execute(env) ).to eq(120.0) end end