123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- class Parser
- def initialize(lexer)
- @lexer = lexer
- @current_token = @lexer.get_token
- end
-
- def parse
- tree = Array.new
-
- tree << statement until at_end
-
- tree
- end
-
- def statement
- if @current_token.type == TokenKinds::IF
- conditional
- elsif @current_token.type == TokenKinds::LET
- variable_declaration
- elsif @current_token.type == TokenKinds::FUNCTION
- function_definition
- elsif @current_token.type == TokenKinds::CLASS
- class_definition
- elsif @current_token.type == TokenKinds::FOR
- for_loop
- else
- expr = expression
- eat(TokenKinds::SEMICOLON)
- expr
- end
- end
-
- def variable_declaration
- eat(TokenKinds::LET)
- name = identifier
- eat(TokenKinds::EQUALS)
- value = expression
- eat(TokenKinds::SEMICOLON)
- AST::VariableDeclaration.new(name, value)
- end
-
- def function_definition
- eat(TokenKinds::FUNCTION)
- name = identifier
- params = parameters
- body = block
- AST::FunctionDefinition.new(name, params, body)
- end
-
- def class_definition
- eat(TokenKinds::CLASS)
-
- class_name = AST::Identifier.new(eat(TokenKinds::CLASS_NAME).value)
-
- eat(TokenKinds::LBRACE)
-
- members = Array.new
-
- while [TokenKinds::PUBLIC, TokenKinds::PRIVATE].include?(
- @current_token.type
- )
- is_public =
- if @current_token.type == TokenKinds::PUBLIC
- eat(TokenKinds::PUBLIC)
- true
- elsif @current_token.type == TokenKinds::PRIVATE
- eat(TokenKinds::PRIVATE)
- false
- end
-
- while !at_end && true
- name = identifier
- members << AST::Member.new(name, is_public)
- if @current_token.type == TokenKinds::COMMA
- eat(TokenKinds::COMMA)
- else
- break
- end
- end
-
- eat(TokenKinds::SEMICOLON)
- end
-
- methods = Array.new
- while @current_token.type == TokenKinds::FUNCTION
- methods << function_definition
- end
-
- eat(TokenKinds::RBRACE)
-
- AST::ClassDefinition.new(class_name, members, methods)
- end
-
- def conditional
- branches = Array.new
- eat(TokenKinds::IF)
- condition = expression
- block = self.block
- branches << AST::Branch.new(condition, block)
-
- while @current_token.type == TokenKinds::ELSEIF
- eat(TokenKinds::ELSEIF)
- condition = expression
- block = self.block
- branches << AST::Branch.new(condition, block)
- end
-
- if @current_token.type == TokenKinds::ELSE
- eat(TokenKinds::ELSE)
- block = self.block
- branches << AST::Branch.new(AST::Boolean.new(true), block)
- end
-
- AST::Conditional.new(branches)
- end
-
- def for_loop
- eat(TokenKinds::FOR)
- iterator = identifier
- eat(TokenKinds::IN)
- iterable = expression
- body = block
- AST::ForLoop.new(iterator, iterable, body)
- end
-
- def parameters
- params = Array.new
- eat(TokenKinds::LPAREN)
-
- while @current_token.type == TokenKinds::IDENTIFIER
- params << identifier
-
- if @current_token.type == TokenKinds::COMMA
- eat(TokenKinds::COMMA)
- else
- break
- end
- end
-
- eat(TokenKinds::RPAREN)
-
- params
- end
-
- def block
- statements = Array.new
-
- eat(TokenKinds::LBRACE)
- statements << statement until @current_token.type == TokenKinds::RBRACE
- eat(TokenKinds::RBRACE)
-
- AST::Block.new(statements)
- end
-
- def expression
- binary
- end
-
- private
-
- def binary
- left = comparison
-
- if @current_token.type == TokenKinds::OPERATOR
- operator = @current_token.value
- advance
- right = comparison
- AST::Binary.new(operator, left, right)
- else
- left
- end
- end
-
- def comparison
- left = multiplication
-
- if @current_token.type == TokenKinds::OPERATOR &&
- %i[< > <= >=].include?(@current_token.type)
- operator = @current_token.value
- advance
- right = multiplication
- AST::Binary.new(operator, left, right)
- else
- left
- end
- end
-
- def addition
- left = multiplication
-
- if @current_token.type == TokenKinds::OPERATOR &&
- %i[+ -].include?(@current_token.value)
- operator = @current_token.value
- advance
- right = multiplication
- AST::Binary.new(operator, left, right)
- else
- left
- end
- end
-
- def multiplication
- left = unary
-
- if @current_token.type == TokenKinds::OPERATOR &&
- %i[* /].include?(@current_token.value)
- operator = @current_token.value
- advance
- right = unary
- AST::Binary.new(operator, left, right)
- else
- left
- end
- end
-
- def unary
- if @current_token.type == TokenKinds::OPERATOR &&
- %i[- !].include?(@current_token.value)
- operator = eat(TokenKinds::OPERATOR).value
- expr = primary
- AST::Unary.new(operator, expr)
- else
- primary
- end
- end
-
- def primary
- token = @current_token
- expr =
- case token.type
- when TokenKinds::NULL
- advance
- AST::Null.new
- when TokenKinds::BOOLEAN
- advance
- AST::Boolean.new(token.value)
- when TokenKinds::NUMBER
- advance
- AST::Number.new(token.value)
- when TokenKinds::STRING
- advance
- AST::String.new(token.value)
- when TokenKinds::ATOM
- advance
- AST::Atom.new(token.value)
- when TokenKinds::IDENTIFIER
- identifier
- when TokenKinds::LBRACKET
- array
- when TokenKinds::LBRACE
- hash
- when TokenKinds::LPAREN
- eat(TokenKinds::LPAREN)
- e = expression
- eat(TokenKinds::RPAREN)
- e
- when TokenKinds::FUNCTION
- function_expression
- else
- raise "Unexpected token #{token.type}"
- end
-
- if @current_token.type == TokenKinds::LPAREN
- args = arguments
- AST::FunctionCall.new(expr, args)
- elsif @current_token.type == TokenKinds::LBRACKET
- eat(TokenKinds::LBRACKET)
- key = expression
- eat(TokenKinds::RBRACKET)
- AST::Index.new(expr, key)
- else
- expr
- end
- end
-
- def function_expression
- eat(TokenKinds::FUNCTION)
- params = parameters
- body = block
- AST::FunctionDefinition.new(nil, params, body)
- end
-
- def identifier
- token = eat(TokenKinds::IDENTIFIER)
- AST::Identifier.new(token.value)
- end
-
- def array
- elements = Array.new
- eat(TokenKinds::LBRACKET)
-
- until @current_token.type == TokenKinds::RBRACKET
- elements << expression
-
- if @current_token.type == TokenKinds::COMMA
- eat(TokenKinds::COMMA)
- else
- break
- end
- end
-
- eat(TokenKinds::RBRACKET)
-
- AST::Array.new(elements)
- end
-
- def hash
- h = Hash.new
- eat(TokenKinds::LBRACE)
-
- until @current_token.type == TokenKinds::RBRACE
- key = eat(TokenKinds::ATOM).value
- eat(TokenKinds::ROCKET)
- value = expression
-
- h[key] = value
-
- if @current_token.type == TokenKinds::COMMA
- eat(TokenKinds::COMMA)
- else
- break
- end
- end
-
- eat(TokenKinds::RBRACE)
-
- AST::Hash.new(h)
- end
-
- def arguments
- args = Array.new
- eat(TokenKinds::LPAREN)
-
- until @current_token.type == TokenKinds::RPAREN
- args << expression
-
- if @current_token.type == TokenKinds::COMMA
- eat(TokenKinds::COMMA)
- else
- break
- end
- end
-
- eat(TokenKinds::RPAREN)
-
- args
- end
-
- def eat(type)
- token = @current_token
- if token.type == type
- advance
- token
- else
- if token.nil?
- raise "Unexpected #{token.type} - expected #{type}"
- else
- raise "Unexpected #{token.type} - expected #{type}"
- end
- end
- end
-
- def advance
- @current_token = @lexer.get_token
- end
-
- def at_end
- @current_token.type == TokenKinds::EOF
- end
- end
|