# encoding: utf-8 # frozen_string_literal: true module Carbon module Compiler class Parser module Expressions # Parses precedence rules for expressions. module Precedence protected def parse_precedence(expr, prec) left = expr while PRECEDENCE[peek.type] && PRECEDENCE[peek.type] >= prec op = expect peek.type left = case op.type when :< then parse_precedence_less(left) when :"." then parse_precedence_period(left) when :"[" then parse_precedence_access(left) else parse_precedence_op([left, op, parse_expression_primary]) end end left end def parse_precedence_less(left) default = proc { parse_precedence_op([left, :<, parse_expression_primary]) } return default.call unless first(:type).include?(peek.type) && left.respond_to?(:generics) position = @enum.dup name = parse_type case peek.type when :>, :",", :":" then parse_precendence_generic(left, name) else @enum = position parse_precedence_op([left, :<, parse_expression_primary]) end end def parse_precedence_generic(left, name) children = [name] until peek? :> children << Concrete::Type::Generic.new(parse_module_name, []) break unless peek? :"," expect :"," end expect :> if peek?(:"(") # if this is a call, our left should be an attribute children = [] until peek? :")" children << parse_expression break unless peek? :"," expect :"," end expect :")" arguments = Node::Expression::Call::Parameters.new(children) Node::Expression::Call::Unified.new([left.expression, left.name, arguments, generics]) else left.merge(generics: children) end end def parse_precedence_period(left) name = parse_name generics = peek?(:<) ? parse_module_generics : [] if peek?(:"(") parse_precedence_period_call(left, name, generics) else Node::Expression::Call::Attribute.new([left, name, generics]) end end def parse_precedence_access(left, generics = []) children = [] until peek? :"]" children << parse_expression break unless peek? :"," expect :"," end expect :"]" arguments = Node::Expression::Call::Parameters.new(children) Node::Expression::Call::Access.new([left, arguments, generics]) end def parse_precedence_period_call(left, name, generics) l = expect :"(" children = [] until peek? :")" children << parse_expression break unless peek? :"," expect :"," end r = expect :")" arguments = Node::Expression::Call::Parameters.new(children) Node::Expression::Call::Unified.new([left, name, arguments, generics], components: [left, name, l, r]) end def parse_precedence_op(data) left, op, right = *data oprec = PRECEDENCE.fetch(op.type) while PRECEDENCE[peek.type] && (PRECEDENCE[peek.type] > oprec || (RIGHT.include?(peek.type) && PRECEDENCE[peek.type] == oprec)) right = parse_precedence(right, PRECEDENCE[peek.type]) end case op.type when :"=" Node::Expression::Assignment.new([left, op, right]) when :"&&" Node::Expression::Operation::And.new([left, op, right]) when :"||" Node::Expression::Operation::Or.new([left, op, right]) when :"!=" Node::Expression::Operation::Neq.new([left, op, right]) else Node::Expression::Operation::Normal.new([left, op, right]) end end end end end end end