123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- 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
-
- # This is equivalent to the program
- #
- # function add_one(n) {
- # n + 1;
- # }
- # add_one(5);
- # print(n);
- #
- # This test is ensuring that `n` is not still defined outside the scope of
- # add_one after the function finishes executing
- it 'destroys variables when they go out of scope' 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)
-
- AST::FunctionCall.new(
- AST::Identifier.new('add_one'),
- [
- AST::Number.new(5)
- ]
- ).execute(env)
-
- expect do
- AST::FunctionCall.new(
- AST::Identifier.new('print'),
- [
- AST::Identifier.new('n')
- ]
- ).execute(env)
- end.to raise_error('Undefined variable n')
- end
- end
|