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 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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. def self.eval(source, env)
  41. lexer = Lexer.new(source)
  42. tree = Parser.new(lexer).parse
  43. if tree.is_a?(Error)
  44. return tree
  45. end
  46. interpreter = Interpreter.new(tree, env)
  47. interpreter.interpret.first
  48. end
  49. CORE = {
  50. "+" => Proc.new { |args| type_check(args, Float) || args.inject(:+) },
  51. "-" => Proc.new { |args| type_check(args, Float) || args.inject(:-) },
  52. "*" => Proc.new { |args| type_check(args, Float) || args.inject(:*) },
  53. "/" => Proc.new { |args| type_check(args, Float) || args.inject(:/) },
  54. "=" => Proc.new { |args| compare_pairs(args, :==) },
  55. "<" => Proc.new { |args| type_check(args, Float) || compare_pairs(args, :<) },
  56. ">" => Proc.new { |args| type_check(args, Float) || compare_pairs(args, :>) },
  57. "<=" => Proc.new { |args| type_check(args, Float) || compare_pairs(args, :<=) },
  58. ">=" => Proc.new { |args| type_check(args, Float) || compare_pairs(args, :>=) },
  59. "and" => Proc.new { |args| !(args.include?(false)) },
  60. "or" => Proc.new { |args| args.any? { |arg| !!arg == true } },
  61. "not" => Proc.new do |args|
  62. error = arity_check(args, 1)
  63. if error.nil?
  64. args.first == false ? true : false
  65. else
  66. error
  67. end
  68. end,
  69. "car" => Proc.new do |args|
  70. error = arity_check(args, 1)
  71. if error.nil?
  72. error = type_check(args, Array)
  73. if error.nil?
  74. if args.first.empty?
  75. Error.new("`car` expects a non-empty list")
  76. else
  77. args.first.first
  78. end
  79. else
  80. error
  81. end
  82. else
  83. error
  84. end
  85. end,
  86. "cdr" => Proc.new do |args|
  87. error = arity_check(args, 1)
  88. if error.nil?
  89. error = type_check(args, Array)
  90. if error.nil?
  91. args.first[1..-1]
  92. else
  93. error
  94. end
  95. else
  96. error
  97. end
  98. end,
  99. "cons" => Proc.new do |args|
  100. error = arity_check(args, 2)
  101. if error.nil?
  102. el, els = args
  103. error = type_check([els], Array)
  104. if error.nil?
  105. els.prepend(el)
  106. end
  107. end
  108. end,
  109. }
  110. NATIVE_CORE = {
  111. "map" => "(define (map f xs) (if (= xs '()) '() (cons (f (car xs)) (map f (cdr xs)))))"
  112. }
  113. end
  114. end