You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
2.4 KiB

#!/usr/bin/ruby
# encoding: utf-8
require 'antlr3/test/functional'
class TestCalcParser < ANTLR3::Test::Functional
inline_grammar( <<-'END' )
grammar TestCalc;
options { language = Ruby; }
@parser::init {
@reported_errors = []
}
@parser::members {
attr_reader :reported_errors
def emit_error_message(msg)
@reported_errors << msg
end
}
evaluate returns [result]: r=expression { $result = $r.result };
expression returns [result]:
r=mult { $result = $r.result }
(
'+' r2=mult { $result += $r2.result }
| '-' r2=mult { $result -= $r2.result }
)*
;
mult returns [result]:
r=log { $result = $r.result }
(
'*' r2=log {$result *= $r2.result}
| '/' r2=log {$result /= $r2.result}
| '%' r2=log {$result \%= $r2.result}
)*
;
log returns [result]: 'ln' r=exp {$result = Math.log($r.result)}
| r=exp {$result = $r.result}
;
exp returns [result]: r=atom { $result = $r.result } ('^' r2=atom { $result **= $r2.result } )?
;
atom returns [result]:
n=INTEGER {$result = Integer($n.text)}
| n=DECIMAL {$result = Float($n.text)}
| '(' r=expression {$result = $r.result} ')'
| 'PI' {$result = Math::PI}
| 'E' {$result = Math::E}
;
INTEGER: DIGIT+;
DECIMAL: DIGIT+ '.' DIGIT+;
fragment
DIGIT: '0'..'9';
WS: (' ' | '\n' | '\t')+ {$channel = HIDDEN};
END
def evaluate( expression )
lexer = TestCalc::Lexer.new( expression )
parser = TestCalc::Parser.new lexer
value = parser.evaluate
errors = parser.reported_errors
return [ value, errors ]
end
tests = %[
1 + 2 = 3
1 + 2 * 3 = 7
10 / 2 = 5
6 + 2*(3+1) - 4 = 10
].strip!.split( /\n/ ).map { |line|
expr, val = line.strip.split( /\s+=\s+/, 2 )
[ expr, Integer( val ) ]
}
tests.each do |expression, true_value|
example "should parse '#{ expression }'" do
parser_value, errors = evaluate( expression )
parser_value.should == true_value
end
end
example "badly formed input" do
val, errors = evaluate "6 - (2*1"
errors.should have( 1 ).thing
errors.first.should =~ /mismatched/
end
end