Trace
Trace is a distinctive feature of CPLib, which can record the inclusion relationship of variables when they are read in. Through this feature, CPLib can provide a read-in stack trace when an error occurs during variable reading, or convert the input file into a JSON format that is easy to parse.
Introduction
The principle of Trace is to maintain a stack (or a tree at the same time) composed of the inclusion relationship of variables when using cplib::var::Reader::read
to read variables. When a variable is about to be read in, the current line and column position, byte sequence number, variable name, and other information of the input stream are pushed onto the stack (or added as a leaf node to the current node in the tree). When the variable reading is completed, it is popped off the stack (or backtracked to the parent node in the tree).
CPLib has two forms of trace: trace stack and trace tree, corresponding to the stack and tree respectively. Among them, the trace stack only contains basic information about the variables, while the trace tree allows additional JSON tags to be added to the nodes to describe additional information.
JSON Tag
You can add JSON tags to the nodes of the trace tree to describe more detailed information. A JSON tag is a mapping from a string key name to any JSON value supported by CPLib.
When implementing custom types (such as FnVar
or ExtVar
), you can call in.attach_json_tag(key, value)
to customize a key-value pair of additional information (where in
is the current Reader being read). The key
should not be repeated, otherwise the later defined one will overwrite the earlier one.
The built-in variable read-in templates (except cplib::var::Separator
) in CPLib will add a key #t
at the end of the variable reading to indicate the type of the variable. If the read-in type is a basic type or a string, an additional key #v
will be added to indicate the value read-in. The variable read-in templates and the corresponding values of #t
are as follows:
Var | #t |
---|---|
Int | i |
Float | f |
StrictFloat | sf |
YesNo | yn |
String | s |
Line | l |
Vec | v |
Mat | m |
Pair | p |
Tuple | t |
FnVar | F |
ExtVar | E |
#hidden
is a special key, and if this key (regardless of the value) exists in the JSON tag of a node, the nodes in the subtree of the current node will be ignored when encoded as JSON. The variable read-in template cplib::var::Separator
will add #hidden
to the current node when the reading is completed.
Key names starting with #
are all considered reserved or have special purposes by CPLib. It is best not to use special prefixes when customizing additional information.
Interface
The interfaces related to trace in CPLib are as follows.
cplib::var::Reader::TraceLevel
cplib::var::Reader::TraceLevel
represents the trace enablement level of the Reader, with three possible values:
NONE
(0): Completely disable trace.STACK_ONLY
(1): Only enable trace stack.FULL
(2): Enable both trace stack and trace tree.
In the default case of using DefaultInitializer
, the inf reader in validator mode has a FULL
level, while the Reader in other modes has a STACK_ONLY
level.
You can use the CPLIB_VAR_READER_TRACE_LEVEL_MAX
macro to set the maximum trace level used by the DefaultInitializer. The specific method is to add the command line argument -DCPLIB_VAR_READER_TRACE_LEVEL_MAX={int}
at compile time, or define #define CPLIB_VAR_READER_TRACE_LEVEL_MAX {int}
before #include "cplib.h"
.
You can use the cplib::var::Reader::get_trace_level()
method to get the trace level of the Reader.
cplib::var::Reader::Trace
Contains the basic information of a variable:
var_name
: The name of the variable.pos.line
: The line number when the reading started, numbered from 0.pos.col
: The column number when the reading started, numbered from 0.pos.byte
: The byte sequence number when the reading started, numbered from 0.byte_length
: The byte length of the original content corresponding to the variable. Specifically, for variables that have not finished reading, this is 0.
It provides two functions, to_json_incomplete
and to_json_complete
, to encode its own content into JSON, which are suitable for variables that have not finished reading and those that have finished reading, respectively. Among them, to_json_incomplete
will export all fields except byte_length
using the original name; while to_json_complete
will only export the three fields var_name
, byte_num
, and byte_length
, and they will be renamed to n
, b
, and l
respectively to avoid generating too long JSON.
cplib::var::Reader::TraceStack
Records the read-in stack of the current variable, or can also be seen as the chain from the root (not included) to the current node (included) of the read-in tree.
It provides three methods, to_json()
, to_plain_text_lines()
, and to_colored_text_lines()
, to convert it to the corresponding format.
For Readers with STACK_ONLY
or higher level enabled, you can use the cplib::var::Reader::get_trace_stack()
method to get the trace stack of the currently read-in variable.
cplib::var::Reader::TraceTreeNode
Represents a node in the trace tree.
The trace
field records the basic information of the variable in the cplib::var::Reader::Trace
type, and the json_tag
field records the additional information of the variable.
It provides the get_children()
method to get the child nodes of the current node, and the get_parent()
method to get the parent node of the current node, which returns nullptr
if it does not exist.
It also provides the to_json()
method to convert its subtree to JSON.
For Readers with the FULL
level enabled, you can use the cplib::var::Reader::get_trace_tree()
method to get the root node of the trace tree for all variables read-in by that Reader. The Trace variable name of the root node is <root>
.