rpl.rb/lib/rpl/parser.rb

114 lines
3 KiB
Ruby
Raw Normal View History

2022-02-25 20:04:33 +01:00
# frozen_string_literal: true
2022-08-30 14:34:15 +02:00
class RplTypeError < StandardError
attr_reader :reason
def initialize( reason = '-undefined-' )
super
2022-08-30 14:34:15 +02:00
@reason = reason
end
end
2022-02-25 20:04:33 +01:00
class Parser
include Types
def self.parse( input )
unless input.index("\n").nil?
input = input.split("\n")
.map do |line|
2022-03-12 22:20:30 +01:00
comment_begin_index = line.index('@')
2022-02-25 20:04:33 +01:00
case comment_begin_index
when nil
line
when 0
''
else
line[0..(comment_begin_index - 1)]
end
end
.join(' ')
end
splitted_input = input.split(' ')
# 2-passes:
2022-08-31 11:10:33 +02:00
# 1. regroup strings, lists, complexes, names and programs
2022-02-25 20:04:33 +01:00
opened_programs = 0
closed_programs = 0
2022-08-31 11:10:33 +02:00
2022-02-25 20:04:33 +01:00
opened_lists = 0
closed_lists = 0
2022-08-31 11:10:33 +02:00
opened_complexes = 0
closed_complexes = 0
2022-02-25 20:04:33 +01:00
string_delimiters = 0
2022-08-31 11:10:33 +02:00
2022-02-25 20:04:33 +01:00
name_delimiters = 0
2022-08-31 11:10:33 +02:00
2022-02-25 20:04:33 +01:00
regrouping = false
regrouped_input = []
splitted_input.each do |elt|
if elt[0] == '«'
opened_programs += 1
elt.gsub!( '«', '« ') if elt.length > 1 && elt[1] != ' '
elsif elt[0] == '{'
opened_lists += 1
elt.gsub!( '{', '{ ') if elt.length > 1 && elt[1] != ' '
2022-08-31 11:10:33 +02:00
elsif elt[0] == '('
opened_complexes += 1
elt.gsub!( '( ', '(') if elt.length > 1 && elt[1] == ' '
2022-02-25 20:04:33 +01:00
elsif elt[0] == '"' && elt.length > 1
string_delimiters += 1
elsif elt[0] == "'" && elt.length > 1
name_delimiters += 1
end
2022-08-31 11:10:33 +02:00
elt = "#{regrouped_input.pop}#{opened_complexes > closed_complexes ? '' : ' '}#{elt}".strip if regrouping
2022-02-25 20:04:33 +01:00
regrouped_input << elt
case elt[-1]
when '»'
closed_programs += 1
elt.gsub!( '»', ' »') if elt.length > 1 && elt[-2] != ' '
when '}'
closed_lists += 1
elt.gsub!( '}', ' }') if elt.length > 1 && elt[-2] != ' '
2022-08-31 11:10:33 +02:00
when ')'
closed_complexes += 1
elt.gsub!( ' )', ')') if elt.length > 1 && elt[-2] == ' '
2022-02-25 20:04:33 +01:00
when '"'
string_delimiters += 1
when "'"
name_delimiters += 1
end
2022-08-31 11:10:33 +02:00
regrouping = string_delimiters.odd? || name_delimiters.odd? || (opened_programs > closed_programs) || (opened_lists > closed_lists) || (opened_complexes > closed_complexes)
2022-02-25 20:04:33 +01:00
end
# 2. parse
2022-08-30 14:34:15 +02:00
parsed_input = regrouped_input.map do |element|
2022-02-25 20:04:33 +01:00
if RplBoolean.can_parse?( element )
2022-02-28 11:40:47 +01:00
Types.new_object( RplBoolean, element )
2022-02-25 20:04:33 +01:00
elsif RplNumeric.can_parse?( element )
2022-02-28 11:40:47 +01:00
Types.new_object( RplNumeric, element )
2022-08-31 11:10:33 +02:00
elsif RplComplex.can_parse?( element )
Types.new_object( RplComplex, element )
2022-02-25 20:04:33 +01:00
elsif RplList.can_parse?( element )
2022-02-28 11:40:47 +01:00
Types.new_object( RplList, element )
2022-02-25 20:04:33 +01:00
elsif RplString.can_parse?( element )
2022-02-28 11:40:47 +01:00
Types.new_object( RplString, element )
2022-02-25 20:04:33 +01:00
elsif RplProgram.can_parse?( element )
2022-02-28 11:40:47 +01:00
Types.new_object( RplProgram, element )
2022-02-25 20:04:33 +01:00
elsif RplName.can_parse?( element )
2022-02-28 11:40:47 +01:00
Types.new_object( RplName, element )
2022-02-25 20:04:33 +01:00
end
end
2022-08-30 14:34:15 +02:00
parsed_input
2022-02-25 20:04:33 +01:00
end
end