Chervil is a toy Lisp interpreter written in Ruby
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

core.rb 2.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. module Chervil
  2. module Core
  3. def self.compare_pairs(ary, method)
  4. pairs = Array.new
  5. ary.each_with_index do |el, i|
  6. unless ary[i + 1].nil?
  7. pairs.push([el, ary[i + 1]])
  8. end
  9. end
  10. !(pairs.map { |pair| pair[0].send(method, pair[1]) }.any?(false))
  11. end
  12. def self.display_class_name(cls)
  13. case cls.inspect
  14. when "Float"
  15. "number"
  16. when "Array"
  17. "list"
  18. when "String"
  19. "string"
  20. end
  21. end
  22. def self.type_check(args, cls)
  23. args_with_wrong_type = args.select { |arg| !arg.is_a?(cls) }
  24. if args_with_wrong_type.length.zero?
  25. nil
  26. else
  27. expected_type = display_class_name(cls)
  28. received_type = display_class_name(args_with_wrong_type.first.class)
  29. ::Chervil::Error.new("Expected an argument of type #{expected_type} but got #{received_type}")
  30. end
  31. end
  32. def self.arity_check(args, expected_count)
  33. if args.size != expected_count
  34. s = expected_count == 1 ? '' : 's'
  35. Error.new("Expected #{expected_count} argument#{s} but received #{args.size}")
  36. else
  37. nil
  38. end
  39. end
  40. CORE = {
  41. "+" => Proc.new { |args| type_check(args, Float) || args.inject(:+) },
  42. "-" => Proc.new { |args| type_check(args, Float) || args.inject(:-) },
  43. "*" => Proc.new { |args| type_check(args, Float) || args.inject(:*) },
  44. "/" => Proc.new { |args| type_check(args, Float) || args.inject(:/) },
  45. "=" => Proc.new { |args| compare_pairs(args, :==) },
  46. "<" => Proc.new { |args| type_check(args, Float) || compare_pairs(args, :<) },
  47. ">" => Proc.new { |args| type_check(args, Float) || compare_pairs(args, :>) },
  48. "<=" => Proc.new { |args| type_check(args, Float) || compare_pairs(args, :<=) },
  49. ">=" => Proc.new { |args| type_check(args, Float) || compare_pairs(args, :>=) },
  50. "and" => Proc.new { |args| !(args.include?(false)) },
  51. "or" => Proc.new { |args| args.any? { |arg| !!arg == true } },
  52. "not" => Proc.new do |args|
  53. error = arity_check(args, 1)
  54. if error.nil?
  55. args.first == false ? true : false
  56. else
  57. error
  58. end
  59. end,
  60. "car" => Proc.new do |args|
  61. error = arity_check(args, 1)
  62. if error.nil?
  63. error = type_check(args, Array)
  64. if error.nil?
  65. if args.first.empty?
  66. Error.new("`car` expects a non-empty list")
  67. else
  68. args.first.first
  69. end
  70. else
  71. error
  72. end
  73. else
  74. error
  75. end
  76. end,
  77. "cdr" => Proc.new do |args|
  78. error = arity_check(args, 1)
  79. if error.nil?
  80. error = type_check(args, Array)
  81. if error.nil?
  82. args.first[1..-1]
  83. else
  84. error
  85. end
  86. else
  87. error
  88. end
  89. end
  90. }
  91. end
  92. end