From ff8244450564cf9f4027aa291b1e9e09ddeb73c6 Mon Sep 17 00:00:00 2001 From: Christopher Locke Date: Wed, 27 Dec 2017 13:49:37 +0900 Subject: [PATCH] Keywords (let) can be used as functions too --- lib/keisan/functions/let.rb | 6 ++---- lib/keisan/parser.rb | 9 ++++++++- spec/keisan/let_spec.rb | 19 +++++++++++++++++-- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/keisan/functions/let.rb b/lib/keisan/functions/let.rb index 80cf43f..0722e3c 100644 --- a/lib/keisan/functions/let.rb +++ b/lib/keisan/functions/let.rb @@ -6,8 +6,7 @@ def initialize end def value(ast_function, context = nil) - validate_arguments!(ast_function.children.count) - assignment(ast_function).value(context) + evaluate(ast_function, context) end def evaluate(ast_function, context = nil) @@ -16,8 +15,7 @@ def evaluate(ast_function, context = nil) end def simplify(ast_function, context = nil) - validate_arguments!(ast_function.children.count) - assignment(ast_function).simplify(context) + evaluate(ast_function, context) end private diff --git a/lib/keisan/parser.rb b/lib/keisan/parser.rb index 753c92e..e46d0b0 100644 --- a/lib/keisan/parser.rb +++ b/lib/keisan/parser.rb @@ -51,8 +51,15 @@ def parse_multi_line! def parse_keyword! keyword = tokens.first.string + arguments = if tokens[1].is_a?(Tokens::Group) + tokens[1].sub_tokens.split {|token| token.is_a?(Tokens::Comma)}.map {|argument_tokens| + Parsing::Argument.new(argument_tokens) + } + else + Parsing::Argument.new(tokens[1..-1]) + end @components = [ - Parsing::Function.new(keyword, Parsing::Argument.new(tokens[1..-1])) + Parsing::Function.new(keyword, arguments) ] end diff --git a/spec/keisan/let_spec.rb b/spec/keisan/let_spec.rb index 9916a2f..1c54f1b 100644 --- a/spec/keisan/let_spec.rb +++ b/spec/keisan/let_spec.rb @@ -1,17 +1,32 @@ require "spec_helper" RSpec.describe Keisan::Functions::Let do + let(:calculator) { Keisan::Calculator.new } + it "can be used to assign variables" do - calculator = Keisan::Calculator.new calculator.evaluate("let x = 4") expect(calculator.evaluate("2*x")).to eq 8 end it "defines variables locally when in block" do - calculator = Keisan::Calculator.new calculator.evaluate("let x = 7") expect(calculator.evaluate("{let x = 11; x*2}")).to eq 22 expect(calculator.evaluate("x")).to eq 7 end + + it "raises error for single argument when not assignment" do + expect{calculator.evaluate("let x")}.to raise_error(Keisan::Exceptions::InvalidFunctionError) + end + + it "works with two arguments for variable assignment" do + calculator.evaluate("let(x, (10+20))") + expect(calculator.evaluate("x").value).to eq 30 + end + + it "works in sub-expression" do + calculator.evaluate("y = 2*let(x, 3)") + expect(calculator.evaluate("x").value).to eq 3 + expect(calculator.evaluate("y").value).to eq 6 + end end