123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- module Chervil
- class Parser
- def initialize(lexer)
- @lexer = lexer
- @tree = Array.new
- @current_token = @lexer.get_next_token
- @error = nil
- end
-
- def parse
- until @current_token.type == :eof
- @tree << expr
- return @error unless @error.nil?
- end
- @tree
- end
-
- def expr
- if [:string, :number, :boolean].include?(@current_token.type)
- constant
- elsif @current_token.type == :identifier
- identifier
- elsif @current_token.type == :lparen
- application
- else
- @error = Error.new("Unexpected token #{@current_token.type}: #{@current_token.value}")
- end
- end
-
- def application
- eat(:lparen)
-
- if @current_token.type == :identifier && @current_token.value == 'define'
- return definition
- end
-
- expression = expr
-
- args = Array.new
- until @current_token.type == :rparen || @current_token.type == :eof
- args << expr
- end
-
- eat(:rparen)
-
- AST::Application.new(expression, args)
- end
-
- def definition
- eat(:identifier) # the `define`
- if @current_token.type == :identifier
- name = identifier
- value = expr
- eat(:rparen)
- AST::Definition.new(name, value)
- elsif @current_token.type == :lparen
- eat(:lparen)
- name = identifier
- params = Array.new
- until [:rparen, :eof].include?(@current_token.type)
- params << expr
- end
- eat(:rparen)
-
- body = Array.new
- until [:rparen, :eof].include?(@current_token.type)
- body << expr
- end
-
- eat(:rparen)
-
- AST::Definition.new(name, AST::Function.new(name, params, body))
- end
- end
-
- def identifier
- identifier = eat(:identifier)
- AST::Identifier.new(identifier.value)
- end
-
- def constant
- case @current_token.type
- when :number
- token = eat(:number)
- AST::Number.new(token.value.to_f)
- when :string
- token = eat(:string)
- AST::String.new(token.value)
- when :boolean
- token = eat(:boolean)
- AST::Boolean.new(token.value)
- end
- end
-
- def eat(type)
- if @current_token.type == type
- token = @current_token
- @current_token = @lexer.get_next_token
- token
- else
- @error = Error.new("Expected #{type} but got #{@current_token.type}")
- end
- end
- end
- end
|