Browse Source

Add some rudimentary type checking

master
Dylan Baker 5 years ago
parent
commit
85e7554fcd
3 changed files with 36 additions and 9 deletions
  1. 29
    8
      lib/chervil/core.rb
  2. 1
    1
      spec/env_spec.rb
  3. 6
    0
      spec/interpreter_spec.rb

+ 29
- 8
lib/chervil/core.rb View File

@@ -11,16 +11,37 @@ module Chervil
11 11
       !(pairs.map { |pair| pair[0].send(method, pair[1]) }.any?(false))
12 12
     end
13 13
 
14
+    def self.display_class_name(cls)
15
+      case cls.inspect
16
+      when "Float"
17
+        "number"
18
+      when "String"
19
+        "string"
20
+      end
21
+    end
22
+
23
+    def self.type_check(args, cls)
24
+      args_with_wrong_type = args.select { |arg| !arg.is_a?(cls) }
25
+
26
+      if args_with_wrong_type.length.zero?
27
+        nil
28
+      else
29
+        expected_type = display_class_name(cls)
30
+        received_type = display_class_name(args_with_wrong_type.first.class)
31
+        ::Chervil::Error.new("Expected an argument of type #{expected_type} but got #{received_type}")
32
+      end
33
+    end
34
+
14 35
     CORE = {
15
-      "+" => Proc.new { |args| args.inject(:+) },
16
-      "-" => Proc.new { |args| args.inject(:-) },
17
-      "*" => Proc.new { |args| args.inject(:*) },
18
-      "/" => Proc.new { |args| args.inject(:/) },
36
+      "+" => Proc.new { |args| type_check(args, Float) || args.inject(:+) },
37
+      "-" => Proc.new { |args| type_check(args, Float) || args.inject(:-) },
38
+      "*" => Proc.new { |args| type_check(args, Float) || args.inject(:*) },
39
+      "/" => Proc.new { |args| type_check(args, Float) || args.inject(:/) },
19 40
       "=" => Proc.new { |args| compare_pairs(args, :==) },
20
-      "<" => Proc.new { |args| compare_pairs(args, :<) },
21
-      ">" => Proc.new { |args| compare_pairs(args, :>) },
22
-      "<=" => Proc.new { |args| compare_pairs(args, :<=) },
23
-      ">=" => Proc.new { |args| compare_pairs(args, :>=) },
41
+      "<" => Proc.new { |args| type_check(args, Float) || compare_pairs(args, :<) },
42
+      ">" => Proc.new { |args| type_check(args, Float) || compare_pairs(args, :>) },
43
+      "<=" => Proc.new { |args| type_check(args, Float) || compare_pairs(args, :<=) },
44
+      ">=" => Proc.new { |args| type_check(args, Float) || compare_pairs(args, :>=) },
24 45
       "and" => Proc.new { |args| !(args.include?(false)) },
25 46
       "or" => Proc.new { |args| args.any? { |arg| !!arg == true } },
26 47
     }

+ 1
- 1
spec/env_spec.rb View File

@@ -2,7 +2,7 @@ module Chervil
2 2
   RSpec.describe Env do
3 3
     it 'has arithmetic from core' do
4 4
       env = Env.new
5
-      expect(env.get('+').call([1, 2], env)).to eq(3)
5
+      expect(env.get('+').call([1.0, 2.0], env)).to eq(3.0)
6 6
     end
7 7
 
8 8
     it 'inherits from parent env' do

+ 6
- 0
spec/interpreter_spec.rb View File

@@ -32,5 +32,11 @@ module Chervil
32 32
       interpret('(plus-one 5)', env)
33 33
       expect(env.get('x')).to eq(nil)
34 34
     end
35
+
36
+    it 'returns a type error for invalid operation' do
37
+      expect(interpret('(+ 1 "hello")', Env.new).first).to eq(
38
+        Error.new("Expected an argument of type number but got string")
39
+      )
40
+    end
35 41
   end
36 42
 end

Loading…
Cancel
Save