module FixtureFox class TokenizedLine attr_reader :file attr_reader :line attr_reader :lineno attr_reader :initial_indent attr_reader :indent def initialize(file, lineno, initial_indent, indent, line) @file, @line, @lineno, @initial_indent, @indent = file, line.dup, lineno, initial_indent, indent @pos = 1 + @indent # Used to keep track of position for the make_* methods end def error(msg) raise ParseError.new(@file, @lineno, @pos + initial_indent, msg) end def to_s(long: false) if long "#{file}:#{lineno} " else "line #{lineno} " end end protected def make_token(litt) Token.new(file, lineno, initial_indent, @pos, litt) end def make_ident(litt) Ident.new(file, lineno, initial_indent, @pos, litt) end def make_empty(litt) Empty.new(file, lineno, initial_indent, @pos, litt) end def make_value(litt) Value.new(file, lineno, initial_indent, @pos, litt) end def make_directive(litt) Directive.new(file, lineno, initial_indent, @pos, litt) end def make_anchor(litt) AnchorToken.new(@file, @lineno, initial_indent, @pos, litt) end def make_reference(litt) Reference.new(@file, @lineno, initial_indent, @pos, litt) end end class DirectiveLine < TokenizedLine attr_reader :directive # Directive token attr_reader :argument # Value token def initialize(file, lineno, initial_indent, indent, line) super case line when /^(@schema)(\s+)(\w+)\s*(?:#.*)?$/ @directive = make_directive($1) @pos += $1.size + $2.size @argument = make_value($3) when /^(@include)(\s+)(\S+)\s*(?:#.*)?$/ @directive = make_directive($1) @pos += $1.size + $2.size @argument = make_value($3) when /^(@anchors)(\s+)(\S+)\s*(?:#.*)?$/ @directive = make_directive($1) @pos += $1.size + $2.size @argument = make_value($3) else error("Illegal directive") end end def to_s(long: false) super + if long "directive:#{directive.pos} #{directive.litt}, argument:#{argument.pos} #{argument.litt}" else "#{directive.litt} #{argument.litt}" end end end class Line < TokenizedLine attr_reader :dash attr_reader :ident attr_reader :empty # Empty token attr_reader :value attr_reader :reference attr_reader :anchor attr_reader :directive # SchemaDirective token def initialize(file, lineno, initial_indent, indent, line) super # Remove comments not preceded by a quote (' or ") if line =~ /^([^'"#]*?)\s*#.*/ line = $1 end # Parse root element if indent == 0 && line[0] != "-" # Table case line when /^(\w+(?:\.\w+)?)$/ @ident = make_ident($1) return when /^(\w+(?:\.\w+)?)(\s*:\s*)(\[\])$/ @ident = make_ident($1) @pos += $1.size + $2.size @empty = make_empty($3) return end # Check for missing value in root record if line =~ /^(\w+\s*:)$/ error "Table name expected" end end # Parse dash case line when /^-$/ error "Entry content expected" when /^(-\s+)(&\w+.*)/ @dash = make_token("-") @pos += $1.size @anchor = make_anchor($2.sub(/#.*/, "")) return when /^(-\s+)(.*)/ @dash = make_token("-") @pos += $1.size line = $2 when /^-./ @pos += 1 error "Illegal character after '-'" end # Expect key/value pair case line when /^(\w+)(\s*):\s*$/ # Record @ident = make_ident($1) @pos += $1.size + $2.size + 1 when /^(\w+)(\s*:\s*)(&\w+)(\s*)(\S.*)?$/ # Anchor @ident = make_ident($1) @pos += $1.size + $2.size @anchor = make_anchor($3) @pos += $3.size + $4.size $5.nil? or error "Illegal character after anchor" when /^(\w+)(\s*:\s*)(\*.+)(\s*)(\S.*)?/ # Reference @ident = make_ident($1) @pos += $1.size + $2.size @reference = make_reference($3) @pos += $3.size + $4.size $5.nil? or error "Illegal character after reference" when /^(\w+)(\s*:\s*)(["']?.+)/ # Simple value @ident = make_ident($1) @pos += $1.size + $2.size @value = make_value($3) when /^(\w+)(\s*:\s*)(\[.*)/ # Array value @ident = make_ident($1) @pos += $1.size + $2.size litt =~ /.*\]\s*$/ or error "Missing ']'" @value = make_value($3) when /^(\w+)(\s*:\s*)(\{.*)/ # Hash value @ident = make_ident($1) @pos += $1.size + $2.size litt =~ /.*\]\s*$/ or error "Missing '}'" @value = make_value($3) when /^(\*.+)(\s*)(\S.*)?$/ @reference = make_reference($1) @pos += $1.size + $2.size $3.nil? or error "Illegal character after reference" when /^\[.*\]\s*$/ else @pos += line.size error "Missing value" end end # True if the line is the first line of a root table def root_table?() indent == 0 && dash.nil? && value.nil? end # True if the line is the first line of a root record def root_record?() indent == 0 && dash.nil? && !value.nil? || false end # True if the line is the first line of a table element def element?() !dash.nil? end def to_s(long: false) super + if long [ dash && "dash:#{dash.pos}", ident && "ident:#{ident.pos} #{ident.value}", value && "value:#{value.pos} #{value.value}", reference && "reference:#{reference.pos} #{reference.value}", anchor && "anchor:##{anchor.pos} #{anchor.value}" ] else [ dash && "dash", ident && "ident: #{ident.to_s}", value && "value: #{value.to_s}", reference && "reference: #{reference.to_s}", anchor && "anchor: #{anchor.to_s}" ] end.compact.join(", ") end end end