diff --git a/lib/ruby_algebra/command.rb b/lib/ruby_algebra/command.rb index b6ad03c..c9f517e 100644 --- a/lib/ruby_algebra/command.rb +++ b/lib/ruby_algebra/command.rb @@ -19,19 +19,22 @@ module RubyAlgebra def to_s result = "Assignment command: " result += @lhs.is_a?(Array) ? @lhs.join(', ') : @lhs.to_s - result += ' := ' - result += @operand1.to_s - case @operation - when :add - result += ' + ' - when :sub - result += ' - ' - when :mult, :scale - result += ' * ' - when :div - result += ' / ' + if @operation == :diff + result += ' := Diff(' + @operand1.to_s + @operand2.map { |v| ", #{v}"}.join + ')' + else + result += ' := ' + @operand1.to_s + case @operation + when :add + result += ' + ' + when :sub + result += ' - ' + when :mult, :scale + result += ' * ' + when :div + result += ' / ' + end + result += @operand2.to_s if @operation != :assign end - result += @operand2.to_s if @operation != :assign result end end diff --git a/lib/ruby_algebra/parser.rb b/lib/ruby_algebra/parser.rb index 656dfa5..80ef029 100644 --- a/lib/ruby_algebra/parser.rb +++ b/lib/ruby_algebra/parser.rb @@ -141,7 +141,7 @@ module RubyAlgebra token = IdentifierToken.new(@expr[@i...j]) @i = j return token - elsif c.match(%r{[+\-*/^():]}) + elsif c.match(%r{[+\-*/^():,]}) puts 'operator' token = nil case c @@ -159,6 +159,8 @@ module RubyAlgebra token = ParenthesisToken.new(false) when ')' token = ParenthesisToken.new(true) + when ',' + token = CommaToken.new end @i += 1 if c == ':' && @expr[@i] == '=' @@ -200,33 +202,68 @@ module RubyAlgebra if tokenizer.lookahead.type == :assign n = tokenizer.next_token operand1 = tokenizer.lookahead - unless operand1.type == :id && !operand1.variable? - return AssignmentCommand.new(left_hand_side, :assign, parse_polynomial(tokenizer), nil) - end - tokenizer.next_token - operator = tokenizer.next_token - raise StandardError, "unexpected token #{operator.type}, expected +, -, * or /" unless [:plus, :minus, :mult, :div].include?(operator.type) - - operand2 = tokenizer.next_token - unless ([:plus, :minus, :mult].include?(operator.type) && operand2.type == :id && !operand2.variable?) || - ([:mult, :div].include?(operator.type) && operand2.type == :num) - raise StandardError, 'unsupported operation or invalid syntax' - end - if operand2.type == :num - if operator.type == :mult - return AssignmentCommand.new(left_hand_side, :scale, operand1.symbol, operand2.value) + if operand1.type == :id && !operand1.variable? + if operand1.symbol == 'Diff' + tokenizer.next_token + n = tokenizer.next_token + unless n.type == :paren && n.closing == false + raise StandardError, "unexpected token #{n.type}, expected (" + end + n = tokenizer.lookahead + if n.type == :id && !n.variable? + tokenizer.next_token + target = n.symbol + else + target = parse_polynomial(tokenizer) + end + diff_variables = [] + while tokenizer.lookahead.type == :comma + tokenizer.next_token + n = tokenizer.next_token + unless n.type == :id && n.variable? + raise StandardError, "unexpected token #{n.type}, expected variable" + end + diff_variables << n.symbol + end + n = tokenizer.next_token + unless n.type == :paren && n.closing == true + raise StandardError, "unexpected token #{n.type}, expected )" + end + unless tokenizer.next_token.type == :end + raise StandardError, "unexpected token at the end" + end + return AssignmentCommand.new(left_hand_side, :diff, target, diff_variables) + elsif operand1.symbol == 'Subs' + raise NotImplementedError else - return AssignmentCommand.new(left_hand_side, :scale, operand1.symbol, 1.0 / operand2.value) - end - elsif operand2.type == :id - case operator.type - when :plus - return AssignmentCommand.new(left_hand_side, :add, operand1.symbol, operand2.symbol) - when :minus - return AssignmentCommand.new(left_hand_side, :sub, operand1.symbol, operand2.symbol) - when :mult - return AssignmentCommand.new(left_hand_side, :mult, operand1.symbol, operand2.symbol) + tokenizer.next_token + operator = tokenizer.next_token + raise StandardError, "unexpected token #{operator.type}, expected +, -, * or /" unless [:plus, :minus, :mult, :div].include?(operator.type) + + operand2 = tokenizer.next_token + unless ([:plus, :minus, :mult].include?(operator.type) && operand2.type == :id && !operand2.variable?) || + ([:mult, :div].include?(operator.type) && operand2.type == :num) + raise StandardError, 'unsupported operation or invalid syntax' + end + if operand2.type == :num + if operator.type == :mult + return AssignmentCommand.new(left_hand_side, :scale, operand1.symbol, operand2.value) + else + return AssignmentCommand.new(left_hand_side, :scale, operand1.symbol, 1.0 / operand2.value) + end + elsif operand2.type == :id + case operator.type + when :plus + return AssignmentCommand.new(left_hand_side, :add, operand1.symbol, operand2.symbol) + when :minus + return AssignmentCommand.new(left_hand_side, :sub, operand1.symbol, operand2.symbol) + when :mult + return AssignmentCommand.new(left_hand_side, :mult, operand1.symbol, operand2.symbol) + end + end end + else + return AssignmentCommand.new(left_hand_side, :assign, parse_polynomial(tokenizer), nil) end elsif tokenizer.lookahead.type == :comma n = tokenizer.next_token