Guest User

Untitled

a guest
Nov 22nd, 2017
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 1.88 KB | None | 0 0
  1. #!/usr/bin/env ruby
  2.  
  3. # Node representing a flat value
  4. class Value
  5. def initialize(value)
  6. @value = value
  7. end
  8.  
  9. def to_ast
  10. @value
  11. end
  12. end
  13.  
  14. # Node representing a list of other nodes.
  15. class Tree
  16. attr_reader :parent
  17.  
  18. def initialize(parent)
  19. @parent = parent
  20. @children = []
  21. end
  22.  
  23. def <<(child)
  24. @children << child
  25. end
  26.  
  27. def to_ast
  28. @children.map(&:to_ast)
  29. end
  30. end
  31.  
  32. # Node having zero or one child and itself as its parent. It is the "empty"
  33. # node the parser always starts with.
  34. class Root
  35. def initialize
  36. @child = nil
  37. end
  38.  
  39. def parent
  40. self
  41. end
  42.  
  43. def <<(child)
  44. @child = child
  45. end
  46.  
  47. def to_ast
  48. @child.to_ast
  49. end
  50. end
  51.  
  52. # Parse a lisp expression, one token at a time.
  53. class Parser
  54. def initialize
  55. @root = Root.new
  56. @current_node = @root
  57. end
  58.  
  59. def <<(token)
  60. case token
  61. when /^\d+$/
  62. insert Value.new(token.to_i)
  63. when '('
  64. nest_more
  65. when ')'
  66. nest_less
  67. else
  68. insert Value.new(token.to_s)
  69. end
  70. end
  71.  
  72. def nest_more
  73. tree = Tree.new @current_node
  74. @current_node << tree
  75. @current_node = tree
  76. end
  77.  
  78. def nest_less
  79. @current_node = @current_node.parent
  80. end
  81.  
  82. def insert(value)
  83. @current_node << value
  84. end
  85.  
  86. def to_ast
  87. @root.to_ast
  88. end
  89. end
  90.  
  91. # Split input strings into tokens, separating with whitespace and splitting on
  92. # parentheses.
  93. class Tokenizer
  94. def tokens_for(input)
  95. input
  96. .split(/(?<=\()|(?=\))|\s+/) # ugly!
  97. .map(&:strip) # handle cases like '( foo )' => ['(', 'foo', ')']
  98. end
  99. end
  100.  
  101. if $PROGRAM_NAME == __FILE__
  102. if ARGV[0] == '-h'
  103. puts "usage: echo '(some lispy :code (here))' | #{$PROGRAM_NAME}"
  104. exit
  105. end
  106.  
  107. parser = Parser.new
  108. tokenizer = Tokenizer.new
  109.  
  110. # TODO: maybe turn this into a REPL (well, once there's an evaluate step)
  111. ARGF.each do |line|
  112. tokenizer.tokens_for(line).each { |token| parser << token }
  113. end
  114.  
  115. p parser.to_ast
  116. end
Add Comment
Please, Sign In to add comment