Chervil is a toy Lisp interpreter written in Ruby
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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. "cons" => Proc.new do |args|
  91. error = arity_check(args, 2)
  92. if error.nil?
  93. el, els = args
  94. error = type_check([els], Array)
  95. if error.nil?
  96. els.prepend(el)
  97. end
  98. end
  99. end
  100. }
  101. end
  102. end