View Source LogicalFile (LogicalFile v1.0.4)

LogicalFile

One file from many

LogicalFile is a way of creating a logical representation of a unit of lines of text (e.g. a source code file) supplied by one or more backing files, presumably separate files on disk. It also provides for a system of macros that can transform the logical text.

A typical use case for LogicalFile would be to implement a compiler that has #include style functionality. The compiler works on the whole text but can translate logical line numbers back to specific files and local line numbers (for example when an error occurs it can pinpoint the specific file and line the error arose in).

Link to this section Summary

Functions

assemble/2 returns a LogicalFile composed of the Sections specified in the second argument. This is mainly intended for internal use when modifying a LogicalFile during macro processing.

contains_source?/2 returns true if at least one section from the given LogicalFile originates from the specified source_path.

insert/3 inserts a new Section into the LogicalFile at the specified logical line number at_line and containing the contents of the source_path.

last_line_number/1 returns the line number of the last line in the specified LogicalFile.

line/2 returns the specified logical line number from the LogicalFile at lno.

lines/1 returns a list of all lines in the LogicalFile in line number order.

lines/2 takes a LogicalFile and a range of logical line numbers and returns a list of tuples in the form {file, line} for the corresponding lines.

partition_sections/2 accepts a list of Sections and a logical line number at_line representing an insertion point. It returns a tuple {sections_before, insert_section, sections_after} by finding the Section containing at_line and partitioning the remaining Sections around it.

read/3 returns a new LogicalFile containing Sections that represent the contents of the file specified by source_path relative to base_path and as modified by the macros it is initialised with.

resolve_line/2 takes a logical line number logical_lno and returns a tuple {file, local_line_no} representing the file and file line number that logical line represents.

section_including_line/2 returns the Section that contains the logical line lno.

sections_in_order/1 takes the Sections backing a LogicalFile and returns them as a list, ordered by the range of logical line numbers they represent.

sections_to_map/1 takes a list of Sections and returns a Map whose keys are the logical line number ranges of the sections, mapped to the corresponding sections.

size/1 returns the number of lines in the LogicalFile.

update_line/3 replaces the content of line lno in the specified LogicalFile by passing the current contents of the line to the specified transformation function. This function is expected to return the new contents of the line.

Link to this section Types

Specs

t() :: %LogicalFile{base_path: nil | binary(), sections: map()}

Link to this section Functions

Link to this function

assemble(base_path, sections)

View Source

assemble/2 returns a LogicalFile composed of the Sections specified in the second argument. This is mainly intended for internal use when modifying a LogicalFile during macro processing.

Link to this function

contains_source?(logical_file, source_path)

View Source

contains_source?/2 returns true if at least one section from the given LogicalFile originates from the specified source_path.

Examples

iex> file = LogicalFile.read("test/support", "main.source")
iex> invalid_path = Path.expand("test/support/player.source")
iex> assert not LogicalFile.contains_source?(file, invalid_path)
iex> valid_path = Path.expand("test/support/main.source")
iex> assert LogicalFile.contains_source?(file, valid_path)
Link to this function

insert(file, source_path, at_line)

View Source

insert/3 inserts a new Section into the LogicalFile at the specified logical line number at_line and containing the contents of the source_path.

It guarantees that all sections and the logical file remains contiguous.

Examples

last_line_number/1 returns the line number of the last line in the specified LogicalFile.

Examples

iex> alias LogicalFile.Section
iex> file = LogicalFile.read("test/support", "main.source")
iex> assert 11 = LogicalFile.last_line_number(file)

line/2 returns the specified logical line number from the LogicalFile at lno.

Example

iex> file = LogicalFile.read("test/support", "main.source")
iex> assert "%(include.source)" = LogicalFile.line(file, 6)

lines/1 returns a list of all lines in the LogicalFile in line number order.

Link to this function

lines(file, logical_line_range)

View Source

lines/2 takes a LogicalFile and a range of logical line numbers and returns a list of tuples in the form {file, line} for the corresponding lines.

Link to this function

partition_sections(sections, at_line)

View Source

partition_sections/2 accepts a list of Sections and a logical line number at_line representing an insertion point. It returns a tuple {sections_before, insert_section, sections_after} by finding the Section containing at_line and partitioning the remaining Sections around it.

Link to this function

read(base_path, source_path, macros \\ [])

View Source

read/3 returns a new LogicalFile containing Sections that represent the contents of the file specified by source_path relative to base_path and as modified by the macros it is initialised with.

Macros should implement the LogicalFile.Macro behaviours and should be specified as a list of tuples of the form {module, [options keyword list]}. See LogicalFile.Macro for further details.

Examples

iex> file = LogicalFile.read("test/support", "main.source")
iex> assert 11 = LogicalFile.size(file)
Link to this function

resolve_line(file, logical_lno)

View Source

resolve_line/2 takes a logical line number logical_lno and returns a tuple {file, local_line_no} representing the file and file line number that logical line represents.

Examples

iex> alias LogicalFile.Macros.Include
iex> file = LogicalFile.read("test/support", "main.source")
iex> path = Path.expand("test/support/main.source")
iex> assert {^path, 1} = LogicalFile.resolve_line(file, 1)
Link to this function

section_including_line(file, lno)

View Source

section_including_line/2 returns the Section that contains the logical line lno.

Examples

iex> alias LogicalFile.Section
iex> section1 = Section.new("test/support/main.source")
iex> section2 = Section.new("test/support/include.source") |> Section.shift(Section.size(section1))
iex> map = LogicalFile.assemble("test/support", [section1, section2])
iex> assert ^section1 = LogicalFile.section_including_line(map, section1.range.first)
iex> assert ^section2 = LogicalFile.section_including_line(map, section2.range.first)
Link to this function

sections_in_order(logical_file)

View Source

sections_in_order/1 takes the Sections backing a LogicalFile and returns them as a list, ordered by the range of logical line numbers they represent.

Link to this function

sections_to_map(sections)

View Source

sections_to_map/1 takes a list of Sections and returns a Map whose keys are the logical line number ranges of the sections, mapped to the corresponding sections.

size/1 returns the number of lines in the LogicalFile.

Examples

iex> file = LogicalFile.read("test/support", "main.source")
iex> 11 = LogicalFile.size(file)
Link to this function

update_line(file, lno, fun)

View Source

update_line/3 replaces the content of line lno in the specified LogicalFile by passing the current contents of the line to the specified transformation function. This function is expected to return the new contents of the line.

Examples

iex> assert "                 " =
...>  LogicalFile.read("test/support", "main.source")
...>  |> LogicalFile.update_line(6, fn line -> String.duplicate(" ", String.length(line)) end)
...>  |> LogicalFile.line(6)