Compare commits
75 Commits
v3.0.1
...
v3.0.2-rc.
Author | SHA1 | Date | |
---|---|---|---|
4a2882711d | |||
08113c961a | |||
e2da46e20a | |||
0cf44da917 | |||
d03638919a | |||
f5d342a442 | |||
06cab2f098 | |||
9d67ae800d | |||
d2a1030320 | |||
5c17d23606 | |||
bc1759aedf | |||
b9aef10db3 | |||
bdb6ac9fba | |||
4d5f935e82 | |||
d604e44dff | |||
2c37da4cb4 | |||
741078c4fd | |||
e101cf2aab | |||
3dfae74468 | |||
2363f42bc9 | |||
491454ca3c | |||
562b2296e5 | |||
3535afb1e1 | |||
7a63e4abb9 | |||
2281cd1cd4 | |||
4037b339e4 | |||
00c3140f3b | |||
0fb282d153 | |||
7a73f99581 | |||
bdd68f04e1 | |||
a5a300b150 | |||
197cec923e | |||
c391a1f566 | |||
1727113a8b | |||
18ac959970 | |||
d00c5bb753 | |||
ffcf07b935 | |||
042531abc3 | |||
4fc7355fba | |||
c12be088c6 | |||
9c3cfe8f7b | |||
d4c168af30 | |||
f2d3aee662 | |||
340db244f6 | |||
8969364f73 | |||
b67168134b | |||
97d33da686 | |||
1f35bda3d2 | |||
6960e8a8c7 | |||
b30cecd297 | |||
99fc6988a3 | |||
cf022f9959 | |||
0a1044743e | |||
94b204615b | |||
230c6dfc15 | |||
8be67e7065 | |||
378b2ae673 | |||
36e517bd80 | |||
569b3d0c97 | |||
daf68d24ab | |||
8a82f52100 | |||
d0864b9efe | |||
18bd606262 | |||
252f50108b | |||
015c34fc2b | |||
d7b47797df | |||
544d4e0635 | |||
73c9d6c1f3 | |||
d9578b6f1c | |||
b5e325cbee | |||
234938349c | |||
9ed7277ec9 | |||
dc87c09442 | |||
00688765fd | |||
3702b72feb |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,5 +1,16 @@
|
||||
# Change Log
|
||||
|
||||
## (unreleased)
|
||||
|
||||
Features:
|
||||
|
||||
* unified translation format for SAS and PDDL files
|
||||
* documentation of `plasp`’s output format
|
||||
|
||||
Bug Fixes:
|
||||
|
||||
* fixes minor formatting issues in SAS translation
|
||||
|
||||
## 3.0.1 (2016-06-14)
|
||||
|
||||
Features:
|
||||
|
54
README.md
54
README.md
@@ -6,8 +6,8 @@
|
||||
|
||||
`plasp` 3 is in early development and not intended for productive use yet.
|
||||
|
||||
`plasp` 3 translates planning problem instances to ASP facts.
|
||||
`plasp` 3 supports the input languages [PDDL](https://helios.hud.ac.uk/scommv/IPC-14/software.html) (only basic features currently) and the [SAS](http://www.fast-downward.org/TranslatorOutputFormat) (full support of the current version 3), which is used by [Fast Downward](http://www.fast-downward.org/).
|
||||
`plasp` translates planning problem instances to ASP facts.
|
||||
`plasp` 3 supports the input languages [PDDL 3.1](https://helios.hud.ac.uk/scommv/IPC-14/software.html) (only basic features currently) and [SAS](http://www.fast-downward.org/TranslatorOutputFormat) (full support of SAS 3), which is used by [Fast Downward](http://www.fast-downward.org/).
|
||||
|
||||
Please get in touch with [Patrick Lühne](https://www.luehne.de) if you have any suggestions.
|
||||
|
||||
@@ -24,7 +24,7 @@ $ plasp domain.pddl problem.pddl
|
||||
Alternatively, PDDL instances may first be translated to SAS, the output format of [Fast Downward](http://www.fast-downward.org/).
|
||||
|
||||
```bash
|
||||
$ ./fast-downward.py --translate --build=release64 domain.pddl instance.pddl
|
||||
$ ./fast-downward.py --translate --build=release64 domain.pddl problem.pddl
|
||||
```
|
||||
|
||||
This creates a file called `output.sas`, which may now be translated by `plasp`.
|
||||
@@ -42,51 +42,29 @@ $ plasp domain.pddl problem.pddl > instance.lp
|
||||
$ clingo encodings/pddl-meta-sequential-incremental.lp instance.lp
|
||||
```
|
||||
|
||||
### Command-Line Interface
|
||||
## Command-Line Interface
|
||||
|
||||
```bash
|
||||
$ plasp [files] [options]
|
||||
```
|
||||
|
||||
`[files]` may be omitted, in which case the input is read from `std::cin`.
|
||||
The `[options]` are listed below:
|
||||
`plasp` automatically detects the language of the input program.
|
||||
|
||||
| **option** | **explanation** |
|
||||
|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `-l` [ `--language` ] | Specify the input language (`sas` or `pddl`). Omit for automatic detection. |
|
||||
| `--warning-level` arg (=`normal`) | Specify whether to output warnings normally (`normal`), to treat them as critical errors (`error`), or to ignore them (`ignore`). |
|
||||
| `--color` arg (=`auto`) | Specify whether to colorize the output (`always`, `never`, or `auto`). |
|
||||
See [command-line interface](doc/command-line-interface.md) for more detail.
|
||||
|
||||
## Output Format
|
||||
|
||||
`plasp` provides a uniform output format for SAS and PDDL input problems.
|
||||
|
||||
See [output format](doc/output-format.md) for more detail.
|
||||
|
||||
If you want to write your own meta encoding for `plasp`’s output, this [simple example encoding](encodings/sequential-incremental.lp) gets you started.
|
||||
|
||||
## Building
|
||||
|
||||
`plasp` requires a C++14 compiler (preferrably GCC ≥ 6.1 or clang ≥ 3.8), the `boost` libraries (≥ 1.55), and CMake for building.
|
||||
`plasp` requires `boost` and is built via CMake and a C++ compiler.
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/potassco/plasp.git
|
||||
$ cd plasp
|
||||
$ mkdir -p build/release
|
||||
$ cd build/release
|
||||
$ cmake ../.. -DCMAKE_BUILD_TYPE=Release
|
||||
$ make
|
||||
```
|
||||
|
||||
The built `plasp` binary is then located at `plasp/build/release/bin/plasp`.
|
||||
|
||||
### Running the Tests
|
||||
|
||||
`plasp` provides unit tests written using the [Google Test](https://github.com/google/googletest) framework.
|
||||
Before building and running the tests, make sure you have fetched the Google Test git submodule:
|
||||
|
||||
```bash
|
||||
$ git submodule init
|
||||
$ git submodule update
|
||||
```
|
||||
|
||||
Afterward, build and run the tests as follows:
|
||||
|
||||
```bash
|
||||
$ make run-tests
|
||||
```
|
||||
See [building instructions](doc/building-instructions.md) for more detail.
|
||||
|
||||
## Contributors
|
||||
|
||||
|
@@ -66,7 +66,7 @@ int main(int argc, char **argv)
|
||||
|
||||
if (variablesMap.count("version"))
|
||||
{
|
||||
std::cout << "plasp version 3.0.1" << std::endl;
|
||||
std::cout << "plasp version 3.0.2-rc.1" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -104,9 +104,7 @@ int main(int argc, char **argv)
|
||||
|
||||
try
|
||||
{
|
||||
plasp::utils::Parser parser;
|
||||
|
||||
parser.setCaseSensitive(false);
|
||||
plasp::utils::Parser<plasp::utils::CaseInsensitiveParserPolicy> parser;
|
||||
|
||||
if (variablesMap.count("input"))
|
||||
{
|
||||
@@ -115,11 +113,11 @@ int main(int argc, char **argv)
|
||||
std::for_each(inputFiles.cbegin(), inputFiles.cend(),
|
||||
[&](const auto &inputFile)
|
||||
{
|
||||
parser.readFile(inputFile);
|
||||
parser.read(inputFile);
|
||||
});
|
||||
}
|
||||
else
|
||||
parser.readStream("std::cin", std::cin);
|
||||
parser.read("std::cin", std::cin);
|
||||
|
||||
const auto detectLanguage =
|
||||
[&]()
|
||||
|
40
doc/building-instructions.md
Normal file
40
doc/building-instructions.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Building Instructions
|
||||
|
||||
`plasp` requires a C++14 compiler (preferrably GCC ≥ 6.1 or clang ≥ 3.8), the `boost` libraries (≥ 1.55), and CMake for building.
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/potassco/plasp.git
|
||||
$ cd plasp
|
||||
$ mkdir -p build/release
|
||||
$ cd build/release
|
||||
$ cmake ../.. -DCMAKE_BUILD_TYPE=Release
|
||||
$ make
|
||||
```
|
||||
|
||||
The built `plasp` binary is then located at `plasp/build/release/bin/plasp`.
|
||||
|
||||
To update `plasp` to the most recent version, perform the following steps:
|
||||
|
||||
```bash
|
||||
$ cd plasp
|
||||
$ git pull
|
||||
$ cd build/release
|
||||
$ cmake .
|
||||
$ make
|
||||
```
|
||||
|
||||
## Running the Tests
|
||||
|
||||
`plasp` provides unit tests written using the [Google Test](https://github.com/google/googletest) framework.
|
||||
Before building and running the tests, make sure you have fetched the Google Test git submodule:
|
||||
|
||||
```bash
|
||||
$ git submodule init
|
||||
$ git submodule update
|
||||
```
|
||||
|
||||
Afterward, build and run the tests as follows:
|
||||
|
||||
```bash
|
||||
$ make run-tests
|
||||
```
|
18
doc/command-line-interface.md
Normal file
18
doc/command-line-interface.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Command-Line Interface
|
||||
|
||||
```bash
|
||||
$ plasp [files] [options]
|
||||
```
|
||||
|
||||
`plasp` automatically detects the language of the input files.
|
||||
|
||||
Multiple files may be provided in an arbitrary order.
|
||||
`[files]` may also be omitted, in which case the input is read from `std::cin`.
|
||||
|
||||
`plasp` supports the following options:
|
||||
|
||||
| **option** | **explanation** |
|
||||
|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `-l` [ `--language` ] | Specify the input language (`sas` or `pddl`). Omit for automatic detection. |
|
||||
| `--warning-level` arg (=`normal`) | Specify whether to output warnings normally (`normal`), to treat them as critical errors (`error`), or to ignore them (`ignore`). |
|
||||
| `--color` arg (=`auto`) | Specify whether to colorize the output (`always`, `never`, or `auto`). |
|
22
doc/feature-requirements.md
Normal file
22
doc/feature-requirements.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Feature Requirements
|
||||
|
||||
Feature requirements are part of `plasp`’s [output format](output-format.md).
|
||||
Currently, `plasp` detects feature requirements only for SAS problems.
|
||||
|
||||
`plasp` supports the following feature requirements:
|
||||
|
||||
SAS feature | description
|
||||
------------|------------
|
||||
`actionCosts` | actions have associated costs (see [action costs](output-format.md#action-costs))
|
||||
`axiomRules` | immediate actions are used, which are executed as soon as the preconditions are satisfied (see [axiom rules](output-format.md#axiom-rules))
|
||||
`conditionalEffects` | some effects of an action may have additional conditions (see [actions](output-format.md#actions))
|
||||
|
||||
## Example
|
||||
|
||||
The following specifies that the input problem has the two requirements `actionCosts` and `conditionalEffects`.
|
||||
|
||||
```prolog
|
||||
% requirements
|
||||
requiresFeature(actionCosts).
|
||||
requiresFeature(conditionalEffects).
|
||||
```
|
202
doc/output-format.md
Normal file
202
doc/output-format.md
Normal file
@@ -0,0 +1,202 @@
|
||||
# Output Format
|
||||
|
||||
`plasp` 3 translates SAS and PDDL files into a uniform ASP fact format.
|
||||
|
||||
## Overview
|
||||
|
||||
Essentially, `plasp`’s output format consists of [state variables](#variables) that are modified by [actions](#actions) if their preconditions are fulfilled.
|
||||
Variables reference [entities](#constants-objects) that are affected by the actions.
|
||||
As with PDDL, the objective is to achieve a specific [goal](#goal) starting from an [initial state](#initial-state) by executing a sequence of actions.
|
||||
|
||||
`plasp`’s variables correspond to the multivalued variables in SAS.
|
||||
PDDL predicates are turned into Boolean variables to make the output format consistent.
|
||||
|
||||
Actions are modeled exactly as PDDL actions and SAS operators.
|
||||
|
||||
## In a Nutshell
|
||||
|
||||
The following illustrates `plasp`’s output format for the problem of turning switches on and off.
|
||||
|
||||
```prolog
|
||||
% declares the type "type(switch)"
|
||||
type(type(switch)).
|
||||
|
||||
% introduces a switch "constant(a)"
|
||||
constant(constant(a)).
|
||||
has(constant(a), type(switch)).
|
||||
|
||||
% declares a variable "variable(on(X))" for switches X
|
||||
variable(variable(on(X))) :- has(X, type(switch)).
|
||||
|
||||
% the variable may be true or false
|
||||
contains(variable(on(X)), value(on(X)), true)) :- has(X, type(switch)).
|
||||
contains(variable(on(X)), value(on(X)), false)) :- has(X, type(switch)).
|
||||
|
||||
% declares the action "action(turnOn(X))", which requires switch X to be off and then turns it on
|
||||
action(action(turnOn(X))) :- has(X, type(switch)).
|
||||
precondition(action(turnOn(X)), variable(on(X)), value(on(X), false)) :- has(X, type(switch)).
|
||||
postcondition(action(turnOn(X)), effect(0), variable(on(X)), value(on(X), true)) :- has(X, type(switch)).
|
||||
|
||||
% initially, the switch is off
|
||||
initialState(variable(on(constant(a))), value(on(constant(a)), false)).
|
||||
|
||||
% in the end, the switch should be on
|
||||
goal(variable(on(constant(a))), value(on(constant(a)), true)).
|
||||
```
|
||||
|
||||
## Syntax and Semantics
|
||||
|
||||
`plasp` structures the translated ASP facts into multiple sections, which are explained in the following.
|
||||
|
||||
### Feature Requirements
|
||||
|
||||
```prolog
|
||||
% declares a required feature
|
||||
requires(feature(<name>)).
|
||||
```
|
||||
|
||||
`plasp` recognizes and declares advanced features used by the input problem, such as conditional effects, [mutex groups](#mutex-groups) and [axiom rules](#axiom-rules) (currently only SAS).
|
||||
See the [full list of supported features](feature-requirements.md) for more information.
|
||||
|
||||
The feature requirement predicates may be used in meta encodings to warn about unsupported features.
|
||||
|
||||
### Types
|
||||
|
||||
```prolog
|
||||
% declares a <type>
|
||||
type(type(<name>)).
|
||||
|
||||
% specifies <constant> to be of type type(<name>)
|
||||
has(<constant>, type(<name>)).
|
||||
```
|
||||
|
||||
[Variables](#variables), [constants](#constants-objects), and [objects](#constants-objects) may be typed. Types are only available with PDDL and if typing is enabled.
|
||||
|
||||
### Variables
|
||||
|
||||
```prolog
|
||||
% declares a <variable>
|
||||
variable(variable(<name>)).
|
||||
|
||||
% adds a <value> to the domain of a <variable>
|
||||
contains(<variable>, <value>).
|
||||
```
|
||||
|
||||
`plasp`’s variables represent the current state of the planning problem.
|
||||
Variables are linked to the problem's [objects](#constants-objects) and [constants](#constants-objects).
|
||||
|
||||
`plasp`’s variables are multivalued, and each variable has exactly one value at each point in time.
|
||||
|
||||
With SAS, variable names are numbers starting at 0, `variable(<number>)`.
|
||||
SAS variables are inherently multivalued, which results in two or more values of the form `value(<SAS predicate>, <bool>)` for each variable.
|
||||
|
||||
With PDDL, Boolean variables are created from the PDDL predicates.
|
||||
Variables ared named after the PDDL predicates, `variable(<PDDL predicate>).`
|
||||
Each variable contains exactly two values (one `true`, one `false`) of the form `value(<PDDL predicate>, <bool>)`.
|
||||
Note that with PDDL, variables and values are named identically.
|
||||
|
||||
### Actions
|
||||
|
||||
```prolog
|
||||
% declares an <action>
|
||||
action(action(<name>)).
|
||||
|
||||
% defines that as a precondition to <action>, <variable> must have value <value>
|
||||
precondition(<action>, <variable>, <value>).
|
||||
|
||||
% defines that after applying <action>, <variable> is assigned <value>
|
||||
postcondition(<action>, effect(<number>), <variable>, <value>).
|
||||
|
||||
% defines the condition of a conditional effect
|
||||
precondition(effect(<number>), <variable>, <value>).
|
||||
|
||||
% specifies the costs of applying <action>
|
||||
costs(<action>, <number>).
|
||||
```
|
||||
|
||||
Actions may require certain variables to have specific values in order to be executed.
|
||||
After applying an action, variables get new values according to the action's postconditions.
|
||||
|
||||
Actions may have *conditional effects*, that is, certain postconditions are only applied if additional conditions are satisfied.
|
||||
For this reason, each conditional effect is uniquely identified with a predicate `effect(<number>)` as the second argument of the `postcondition` facts.
|
||||
The conditions of conditional effects are given by additional `precondition` facts that take the respective `effect(<number>)` predicates as the first argument.
|
||||
|
||||
Unconditional effects are identified with `effect(unconditional)`.
|
||||
|
||||
Conditional effects are currently only supported with SAS input problems.
|
||||
|
||||
Actions may also have *action costs* required to apply them. Action costs are currently supported for SAS only.
|
||||
|
||||
### Constants/Objects
|
||||
|
||||
```prolog
|
||||
% declares a <constant> or object
|
||||
constant(constant(<name>)).
|
||||
|
||||
% specifies <constant> to be of type type(<name>)
|
||||
has(<constant>, <type>).
|
||||
```
|
||||
|
||||
Constants and objects are the entities that are affected by [actions](#actions), for instance, the blocks in a Blocks World problem.
|
||||
Constants are global for a domain, while objects are problem-specific.
|
||||
|
||||
`plasp` does not distinguish between the two (modeling both as constants), as both are identically used static identifiers.
|
||||
|
||||
### Initial State
|
||||
|
||||
```prolog
|
||||
% initializes <variable> with a specific <value>
|
||||
initialState(<variable>, <value>).
|
||||
```
|
||||
|
||||
The initial state contains all [variable](#variables) assignments that hold before executing any [actions](#actions).
|
||||
|
||||
Note that with PDDL, the initial state might not assign values to all variables. Instead, unassigned values have to be assigned `false` manually.
|
||||
|
||||
### Goal
|
||||
|
||||
```prolog
|
||||
% specifies that <variable> shall obtain <value> in the end
|
||||
goal(<variable>, <value>).
|
||||
```
|
||||
|
||||
The goal specifies all variable assignments that have to be fulfilled after executing the plan.
|
||||
|
||||
### Mutex Groups
|
||||
|
||||
```prolog
|
||||
% declares a <mutex group>
|
||||
mutexGroup(mutexGroup(<number>)).
|
||||
|
||||
% adds the assignment of <variable> to <value> to a <mutex group>
|
||||
contains(<mutex group>, <variable>, <value>).
|
||||
```
|
||||
|
||||
SAS contains information about mutually exclusive [variable](#variables) assignments.
|
||||
That is, *at most one* variable assignment of each mutex group must be satisfied at all times.
|
||||
|
||||
Mutex group facts are only present with SAS input programs and not PDDL.
|
||||
|
||||
Mutex groups contain essential information in order to find plans correctly.
|
||||
That is, if mutex groups are present in `plasp`’s output, they have to be accounted for appropriately.
|
||||
|
||||
### Axiom Rules
|
||||
|
||||
```prolog
|
||||
% declares an <axiom rule>
|
||||
axiomRule(axiomRule(<number>)).
|
||||
|
||||
% defines that as a precondition to <axiom rule>, <variable> must have value <value>
|
||||
precondition(<axiom rule>, <variable>, <value>).
|
||||
|
||||
% defines that after applying <axiom rule>, <variable> is assigned <value>
|
||||
postcondition(<axiom rule>, <variable>, <value>).
|
||||
```
|
||||
|
||||
Axiom rules are similar to [actions](#actions) in that they modify [variables](#variables) if certain preconditions are satisfied.
|
||||
However, axiom rules must be applied *immediately* as soon as their preconditions are satisfied.
|
||||
|
||||
Axiom rule facts are only present with SAS input programs and not PDDL.
|
||||
|
||||
Axiom rules contain essential information in order to find plans correctly.
|
||||
That is, if axiom rules are present in `plasp`’s output, they have to be accounted for appropriately.
|
@@ -1,31 +0,0 @@
|
||||
#include <incmode>.
|
||||
|
||||
#program base.
|
||||
|
||||
% Establish initial state
|
||||
holds(Predicate, 0) :- initialState(Predicate).
|
||||
|
||||
#program step(t).
|
||||
|
||||
% Perform actions
|
||||
1 {occurs(action(Action), t) : action(Action)} 1.
|
||||
|
||||
% Check preconditions
|
||||
:- occurs(Action, t), precondition(Action, Predicate, true), not holds(Predicate, t - 1).
|
||||
:- occurs(Action, t), precondition(Action, Predicate, false), holds(Predicate, t - 1).
|
||||
|
||||
% Apply effects
|
||||
caused(Predicate, true, t) :- occurs(Action, t), postcondition(Action, Predicate, true).
|
||||
caused(Predicate, false, t) :- occurs(Action, t), postcondition(Action, Predicate, false).
|
||||
|
||||
holds(Predicate, t) :- caused(Predicate, true, t).
|
||||
holds(Predicate, t) :- holds(Predicate, t - 1), not caused(Predicate, false, t).
|
||||
|
||||
#program check(t).
|
||||
|
||||
% Verify that goal is met
|
||||
:- query(t), goal(Predicate, true), not holds(Predicate, t).
|
||||
:- query(t), goal(Predicate, false), holds(Predicate, t).
|
||||
|
||||
#show query/1.
|
||||
#show occurs/2.
|
@@ -1,40 +0,0 @@
|
||||
#include <incmode>.
|
||||
|
||||
% Check feature requirements
|
||||
:- requiresFeature(actionCosts).
|
||||
:- requiresFeature(axiomRules).
|
||||
:- requiresFeature(conditionalEffects).
|
||||
|
||||
#program base.
|
||||
|
||||
% Establish initial state
|
||||
holds(Var, Val, 0) :- initialState(Var, Val).
|
||||
|
||||
#program step(t).
|
||||
|
||||
% Perform actions
|
||||
1 {occurs(action(A), t) : action(A)} 1.
|
||||
|
||||
% Check preconditions
|
||||
:- occurs(A, t), precondition(A, Var, Val), not holds(Var, Val, t - 1).
|
||||
|
||||
% Apply effects
|
||||
caused(Var, Val, t) :- occurs(A, t), postcondition(A, _, Var, Val).
|
||||
modified(Var, t) :- caused(Var, Val, t).
|
||||
|
||||
holds(Var, Val, t) :- caused(Var, Val, t).
|
||||
holds(Var, Val, t) :- holds(Var, Val, t - 1), not modified(Var, t).
|
||||
|
||||
% Check that variables have unique values
|
||||
:- variable(X), Var = variable(X), not 1 {holds(Var, Val, t) : contains(Var, Val)} 1.
|
||||
|
||||
% Check mutexes
|
||||
:- mutexGroup(X), M = mutexGroup(X), not {holds(Var, Val, t) : contains(M, Var, Val)} 1.
|
||||
|
||||
#program check(t).
|
||||
|
||||
% Verify that goal is met
|
||||
:- query(t), goal(Var, Val), not holds(Var, Val, t).
|
||||
|
||||
#show query/1.
|
||||
#show occurs/2.
|
43
encodings/sequential-incremental.lp
Normal file
43
encodings/sequential-incremental.lp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include <incmode>.
|
||||
|
||||
% Check feature requirements
|
||||
:- requiresFeature(actionCosts).
|
||||
:- requiresFeature(axiomRules).
|
||||
:- requiresFeature(conditionalEffects).
|
||||
|
||||
#program base.
|
||||
|
||||
% Establish initial state
|
||||
holds(Variable, Value, 0) :- initialState(Variable, Value).
|
||||
|
||||
% Make unspecified initial state variables false by default (for PDDL)
|
||||
holds(variable(Variable), value(Variable, false), 0) :- variable(variable(Variable)), {initialState(variable(Variable), _)} 0.
|
||||
|
||||
#program step(t).
|
||||
|
||||
% Perform actions
|
||||
1 {occurs(Action, t) : action(Action)} 1.
|
||||
|
||||
% Check preconditions
|
||||
:- occurs(Action, t), precondition(Action, Variable, Value), not holds(Variable, Value, t - 1).
|
||||
|
||||
% Apply effects
|
||||
caused(Variable, Value, t) :- occurs(Action, t), postcondition(Action, _, Variable, Value).
|
||||
modified(Variable, t) :- caused(Variable, Value, t).
|
||||
|
||||
holds(Variable, Value, t) :- caused(Variable, Value, t).
|
||||
holds(Variable, Value, t) :- holds(Variable, Value, t - 1), not modified(Variable, t).
|
||||
|
||||
% Check that variables have unique values
|
||||
:- variable(Variable), not 1 {holds(Variable, Value, t) : contains(Variable, Value)} 1.
|
||||
|
||||
% Check mutexes
|
||||
:- mutexGroup(MutexGroup), not {holds(Variable, Value, t) : contains(MutexGroup, Variable, Value)} 1.
|
||||
|
||||
#program check(t).
|
||||
|
||||
% Verify that goal is met
|
||||
:- query(t), goal(Variable, Value), not holds(Variable, Value, t).
|
||||
|
||||
#show query/1.
|
||||
#show occurs/2.
|
@@ -13,15 +13,14 @@ namespace plasp
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Language::Type detectLanguage(utils::Parser &parser)
|
||||
Language::Type detectLanguage(utils::Parser<utils::CaseInsensitiveParserPolicy> &parser)
|
||||
{
|
||||
parser.setCaseSensitive(false);
|
||||
parser.skipWhiteSpace();
|
||||
|
||||
// SAS begins with "begin_version"
|
||||
if (parser.probe<std::string>("begin"))
|
||||
if (parser.testAndSkip<std::string>("begin"))
|
||||
{
|
||||
parser.seek(std::ios::beg);
|
||||
parser.seek(0);
|
||||
return Language::Type::SAS;
|
||||
}
|
||||
|
||||
@@ -33,7 +32,7 @@ Language::Type detectLanguage(utils::Parser &parser)
|
||||
}
|
||||
|
||||
// PDDL contains sections starting with "(define"
|
||||
if (parser.probe<std::string>("(") && parser.probe<std::string>("define"))
|
||||
if (parser.testAndSkip<std::string>("(") && parser.testAndSkip<std::string>("define"))
|
||||
{
|
||||
parser.seek(std::ios::beg);
|
||||
return Language::Type::PDDL;
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <plasp/pddl/Parser.h>
|
||||
#include <plasp/utils/Logger.h>
|
||||
|
||||
namespace plasp
|
||||
@@ -22,20 +23,21 @@ class Context
|
||||
{
|
||||
public:
|
||||
Context() = default;
|
||||
~Context() = default;
|
||||
|
||||
explicit Context(utils::Parser &&parser)
|
||||
: parser{std::move(parser)}
|
||||
explicit Context(Parser &&otherParser)
|
||||
: parser{std::move(otherParser)}
|
||||
{
|
||||
}
|
||||
|
||||
explicit Context(utils::Logger &&logger)
|
||||
: logger{std::move(logger)}
|
||||
explicit Context(utils::Logger &&otherLogger)
|
||||
: logger{std::move(otherLogger)}
|
||||
{
|
||||
}
|
||||
|
||||
explicit Context(utils::Parser &&parser, utils::Logger &&logger)
|
||||
: parser{std::move(parser)},
|
||||
logger{std::move(logger)}
|
||||
explicit Context(Parser &&otherParser, utils::Logger &&otherLogger)
|
||||
: parser{std::move(otherParser)},
|
||||
logger{std::move(otherLogger)}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -56,7 +58,7 @@ class Context
|
||||
return *this;
|
||||
}
|
||||
|
||||
utils::Parser parser;
|
||||
Parser parser;
|
||||
utils::Logger logger;
|
||||
};
|
||||
|
||||
|
@@ -45,9 +45,9 @@ class Description
|
||||
|
||||
Context m_context;
|
||||
|
||||
utils::Parser::Position m_domainPosition;
|
||||
utils::Stream::Position m_domainPosition;
|
||||
std::unique_ptr<Domain> m_domain;
|
||||
utils::Parser::Position m_problemPosition;
|
||||
utils::Stream::Position m_problemPosition;
|
||||
std::unique_ptr<Problem> m_problem;
|
||||
};
|
||||
|
||||
|
@@ -4,10 +4,11 @@
|
||||
#include <plasp/pddl/Action.h>
|
||||
#include <plasp/pddl/Context.h>
|
||||
#include <plasp/pddl/Expression.h>
|
||||
#include <plasp/pddl/Parser.h>
|
||||
#include <plasp/pddl/Requirement.h>
|
||||
#include <plasp/pddl/expressions/Constant.h>
|
||||
#include <plasp/pddl/expressions/PredicateDeclaration.h>
|
||||
#include <plasp/pddl/expressions/PrimitiveType.h>
|
||||
#include <plasp/pddl/Requirement.h>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
@@ -68,19 +69,19 @@ class Domain
|
||||
|
||||
std::string m_name;
|
||||
|
||||
utils::Parser::Position m_requirementsPosition;
|
||||
utils::Stream::Position m_requirementsPosition;
|
||||
Requirements m_requirements;
|
||||
|
||||
utils::Parser::Position m_typesPosition;
|
||||
utils::Stream::Position m_typesPosition;
|
||||
expressions::PrimitiveTypes m_types;
|
||||
|
||||
utils::Parser::Position m_constantsPosition;
|
||||
utils::Stream::Position m_constantsPosition;
|
||||
expressions::Constants m_constants;
|
||||
|
||||
utils::Parser::Position m_predicatesPosition;
|
||||
utils::Stream::Position m_predicatesPosition;
|
||||
expressions::PredicateDeclarations m_predicates;
|
||||
|
||||
std::vector<utils::Parser::Position> m_actionPositions;
|
||||
std::vector<utils::Stream::Position> m_actionPositions;
|
||||
std::vector<std::unique_ptr<Action>> m_actions;
|
||||
};
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <plasp/utils/Parser.h>
|
||||
#include <plasp/pddl/Parser.h>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
@@ -16,7 +16,7 @@ namespace pddl
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void skipSection(utils::Parser &parser)
|
||||
inline void skipSection(Parser &parser)
|
||||
{
|
||||
size_t openParentheses = 1;
|
||||
|
||||
|
49
include/plasp/pddl/Parser.h
Normal file
49
include/plasp/pddl/Parser.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef __PLASP__PDDL__PARSER_H
|
||||
#define __PLASP__PDDL__PARSER_H
|
||||
|
||||
#include <plasp/utils/Parser.h>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
namespace pddl
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Parser
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class PDDLParserPolicy
|
||||
{
|
||||
public:
|
||||
static char transformCharacter(char c) noexcept
|
||||
{
|
||||
return std::tolower(c);
|
||||
}
|
||||
|
||||
static bool isWhiteSpaceCharacter(char c)
|
||||
{
|
||||
return std::iswspace(c);
|
||||
}
|
||||
|
||||
static bool isIdentifierCharacter(char c)
|
||||
{
|
||||
return c != '?'
|
||||
&& c != '('
|
||||
&& c != ')'
|
||||
&& c != ';'
|
||||
&& std::isgraph(c);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using Parser = utils::Parser<PDDLParserPolicy>;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -4,6 +4,7 @@
|
||||
#include <plasp/pddl/Context.h>
|
||||
#include <plasp/pddl/Expression.h>
|
||||
#include <plasp/pddl/InitialState.h>
|
||||
#include <plasp/pddl/Parser.h>
|
||||
#include <plasp/pddl/Requirement.h>
|
||||
|
||||
namespace plasp
|
||||
@@ -61,18 +62,18 @@ class Problem
|
||||
|
||||
std::string m_name;
|
||||
|
||||
utils::Parser::Position m_domainPosition;
|
||||
utils::Stream::Position m_domainPosition;
|
||||
|
||||
utils::Parser::Position m_requirementsPosition;
|
||||
utils::Stream::Position m_requirementsPosition;
|
||||
Requirements m_requirements;
|
||||
|
||||
utils::Parser::Position m_objectsPosition;
|
||||
utils::Stream::Position m_objectsPosition;
|
||||
expressions::Constants m_objects;
|
||||
|
||||
utils::Parser::Position m_initialStatePosition;
|
||||
utils::Stream::Position m_initialStatePosition;
|
||||
std::unique_ptr<InitialState> m_initialState;
|
||||
|
||||
utils::Parser::Position m_goalPosition;
|
||||
utils::Stream::Position m_goalPosition;
|
||||
ExpressionPointer m_goal;
|
||||
};
|
||||
|
||||
|
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <plasp/pddl/Context.h>
|
||||
#include <plasp/pddl/Expression.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
@@ -57,8 +56,8 @@ AtPointer At::parse(Context &context, ExpressionContext &expressionContext,
|
||||
|
||||
const auto position = parser.position();
|
||||
|
||||
if (!parser.probe<std::string>("(")
|
||||
|| !parser.probeIdentifier("at", isIdentifier))
|
||||
if (!parser.testAndSkip<std::string>("(")
|
||||
|| !parser.testIdentifierAndSkip("at"))
|
||||
{
|
||||
parser.seek(position);
|
||||
return nullptr;
|
||||
@@ -68,9 +67,9 @@ AtPointer At::parse(Context &context, ExpressionContext &expressionContext,
|
||||
|
||||
const auto timePointPosition = parser.position();
|
||||
|
||||
if (parser.probeIdentifier("start", isIdentifier))
|
||||
if (parser.testIdentifierAndSkip("start"))
|
||||
timePoint = TimePointStart;
|
||||
else if (parser.probeIdentifier("end", isIdentifier))
|
||||
else if (parser.testIdentifierAndSkip("end"))
|
||||
timePoint = TimePointEnd;
|
||||
else if (parser.probeNumber())
|
||||
{
|
||||
|
@@ -4,7 +4,6 @@
|
||||
#include <plasp/pddl/ConsistencyException.h>
|
||||
#include <plasp/pddl/Context.h>
|
||||
#include <plasp/pddl/Expression.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/pddl/expressions/Variable.h>
|
||||
|
||||
namespace plasp
|
||||
@@ -52,8 +51,8 @@ std::unique_ptr<Derived> Binary<Derived>::parse(Context &context,
|
||||
|
||||
const auto position = parser.position();
|
||||
|
||||
if (!parser.probe<std::string>("(")
|
||||
|| !parser.probeIdentifier(Derived::Identifier, isIdentifier))
|
||||
if (!parser.testAndSkip<std::string>("(")
|
||||
|| !parser.testIdentifierAndSkip(Derived::Identifier))
|
||||
{
|
||||
parser.seek(position);
|
||||
return nullptr;
|
||||
|
@@ -2,7 +2,6 @@
|
||||
#define __PLASP__PDDL__EXPRESSIONS__CONSTANT_H
|
||||
|
||||
#include <plasp/pddl/Expression.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/utils/Parser.h>
|
||||
#include <plasp/utils/ParserException.h>
|
||||
|
||||
|
@@ -4,7 +4,6 @@
|
||||
#include <plasp/pddl/ConsistencyException.h>
|
||||
#include <plasp/pddl/Context.h>
|
||||
#include <plasp/pddl/Expression.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/pddl/expressions/Variable.h>
|
||||
|
||||
namespace plasp
|
||||
@@ -50,8 +49,8 @@ std::unique_ptr<Derived> NAry<Derived>::parse(Context &context,
|
||||
|
||||
const auto position = parser.position();
|
||||
|
||||
if (!parser.probe<std::string>("(")
|
||||
|| !parser.probeIdentifier(Derived::Identifier, isIdentifier))
|
||||
if (!parser.testAndSkip<std::string>("(")
|
||||
|| !parser.testIdentifierAndSkip(Derived::Identifier))
|
||||
{
|
||||
parser.seek(position);
|
||||
return nullptr;
|
||||
@@ -71,7 +70,7 @@ std::unique_ptr<Derived> NAry<Derived>::parse(Context &context,
|
||||
}
|
||||
|
||||
if (expression->m_arguments.empty())
|
||||
context.logger.logWarning(context.parser, "“" + Derived::Identifier + "” expressions should not be empty");
|
||||
context.logger.logWarning(parser.coordinate(), "“" + Derived::Identifier + "” expressions should not be empty");
|
||||
|
||||
parser.expect<std::string>(")");
|
||||
|
||||
|
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <plasp/pddl/Context.h>
|
||||
#include <plasp/pddl/Expression.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
@@ -50,8 +49,8 @@ NotPointer Not::parse(Context &context, ExpressionContext &expressionContext,
|
||||
|
||||
const auto position = parser.position();
|
||||
|
||||
if (!parser.probe<std::string>("(")
|
||||
|| !parser.probeIdentifier("not", isIdentifier))
|
||||
if (!parser.testAndSkip<std::string>("(")
|
||||
|| !parser.testIdentifierAndSkip("not"))
|
||||
{
|
||||
parser.seek(position);
|
||||
return nullptr;
|
||||
|
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <plasp/pddl/ConsistencyException.h>
|
||||
#include <plasp/pddl/Expression.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/utils/ParserException.h>
|
||||
|
||||
namespace plasp
|
||||
|
@@ -27,8 +27,8 @@ using AssignedVariables = std::vector<AssignedVariable>;
|
||||
class AssignedVariable
|
||||
{
|
||||
public:
|
||||
static AssignedVariable fromSAS(utils::Parser &parser, const Variables &variables);
|
||||
static AssignedVariable fromSAS(utils::Parser &parser, const Variable &variable);
|
||||
static AssignedVariable fromSAS(utils::Parser<> &parser, const Variables &variables);
|
||||
static AssignedVariable fromSAS(utils::Parser<> &parser, const Variable &variable);
|
||||
|
||||
public:
|
||||
explicit AssignedVariable(const Variable &variable, const Value &value);
|
||||
|
@@ -29,7 +29,7 @@ class AxiomRule
|
||||
using Condition = AssignedVariable;
|
||||
using Conditions = AssignedVariables;
|
||||
|
||||
static AxiomRule fromSAS(utils::Parser &parser, const Variables &variables);
|
||||
static AxiomRule fromSAS(utils::Parser<> &parser, const Variables &variables);
|
||||
|
||||
public:
|
||||
const Conditions &conditions() const;
|
||||
|
@@ -29,7 +29,7 @@ namespace sas
|
||||
class Description
|
||||
{
|
||||
public:
|
||||
static Description fromParser(utils::Parser &&parser);
|
||||
static Description fromParser(utils::Parser<> &&parser);
|
||||
static Description fromStream(std::istream &istream);
|
||||
static Description fromFile(const boost::filesystem::path &path);
|
||||
|
||||
@@ -45,19 +45,21 @@ class Description
|
||||
bool usesAxiomRules() const;
|
||||
bool usesConditionalEffects() const;
|
||||
|
||||
bool hasRequirements() const;
|
||||
|
||||
private:
|
||||
Description();
|
||||
|
||||
void parseContent(utils::Parser &parser);
|
||||
void parseContent(utils::Parser<> &parser);
|
||||
|
||||
void parseVersionSection(utils::Parser &parser) const;
|
||||
void parseMetricSection(utils::Parser &parser);
|
||||
void parseVariablesSection(utils::Parser &parser);
|
||||
void parseMutexSection(utils::Parser &parser);
|
||||
void parseInitialStateSection(utils::Parser &parser);
|
||||
void parseGoalSection(utils::Parser &parser);
|
||||
void parseOperatorSection(utils::Parser &parser);
|
||||
void parseAxiomSection(utils::Parser &parser);
|
||||
void parseVersionSection(utils::Parser<> &parser) const;
|
||||
void parseMetricSection(utils::Parser<> &parser);
|
||||
void parseVariablesSection(utils::Parser<> &parser);
|
||||
void parseMutexSection(utils::Parser<> &parser);
|
||||
void parseInitialStateSection(utils::Parser<> &parser);
|
||||
void parseGoalSection(utils::Parser<> &parser);
|
||||
void parseOperatorSection(utils::Parser<> &parser);
|
||||
void parseAxiomSection(utils::Parser<> &parser);
|
||||
|
||||
bool m_usesActionCosts;
|
||||
|
||||
|
@@ -29,7 +29,7 @@ class Effect
|
||||
using Condition = AssignedVariable;
|
||||
using Conditions = AssignedVariables;
|
||||
|
||||
static Effect fromSAS(utils::Parser &parser, const Variables &variables, Conditions &preconditions);
|
||||
static Effect fromSAS(utils::Parser<> &parser, const Variables &variables, Conditions &preconditions);
|
||||
|
||||
public:
|
||||
const Conditions &conditions() const;
|
||||
|
@@ -21,7 +21,7 @@ class Goal
|
||||
using Fact = AssignedVariable;
|
||||
using Facts = AssignedVariables;
|
||||
|
||||
static Goal fromSAS(utils::Parser &parser, const Variables &variables);
|
||||
static Goal fromSAS(utils::Parser<> &parser, const Variables &variables);
|
||||
|
||||
public:
|
||||
const Facts &facts() const;
|
||||
|
@@ -21,7 +21,7 @@ class InitialState
|
||||
using Fact = AssignedVariable;
|
||||
using Facts = AssignedVariables;
|
||||
|
||||
static InitialState fromSAS(utils::Parser &parser, const Variables &variables);
|
||||
static InitialState fromSAS(utils::Parser<> &parser, const Variables &variables);
|
||||
|
||||
public:
|
||||
const Facts &facts() const;
|
||||
|
@@ -28,7 +28,7 @@ class MutexGroup
|
||||
using Fact = AssignedVariable;
|
||||
using Facts = AssignedVariables;
|
||||
|
||||
static MutexGroup fromSAS(utils::Parser &parser, const Variables &variables);
|
||||
static MutexGroup fromSAS(utils::Parser<> &parser, const Variables &variables);
|
||||
|
||||
public:
|
||||
const Facts &facts() const;
|
||||
|
@@ -33,7 +33,7 @@ class Operator
|
||||
using Condition = AssignedVariable;
|
||||
using Conditions = AssignedVariables;
|
||||
|
||||
static Operator fromSAS(utils::Parser &parser, const Variables &variables);
|
||||
static Operator fromSAS(utils::Parser<> &parser, const Variables &variables);
|
||||
|
||||
public:
|
||||
void printPredicateAsASP(utils::LogStream &ostream) const;
|
||||
|
@@ -22,7 +22,7 @@ namespace sas
|
||||
class Predicate
|
||||
{
|
||||
public:
|
||||
static Predicate fromSAS(utils::Parser &parser);
|
||||
static Predicate fromSAS(utils::Parser<> &parser);
|
||||
|
||||
using Arguments = std::vector<std::string>;
|
||||
|
||||
|
@@ -39,8 +39,8 @@ struct Value
|
||||
static const Value Any;
|
||||
static const Value None;
|
||||
|
||||
static Value fromSAS(utils::Parser &parser);
|
||||
static const Value &referenceFromSAS(utils::Parser &parser, const Variable &variable);
|
||||
static Value fromSAS(utils::Parser<> &parser);
|
||||
static const Value &referenceFromSAS(utils::Parser<> &parser, const Variable &variable);
|
||||
|
||||
public:
|
||||
Value negated() const;
|
||||
|
@@ -28,8 +28,8 @@ using Variables = std::vector<Variable>;
|
||||
class Variable
|
||||
{
|
||||
public:
|
||||
static Variable fromSAS(utils::Parser &parser);
|
||||
static const Variable &referenceFromSAS(utils::Parser &parser, const Variables &variables);
|
||||
static Variable fromSAS(utils::Parser<> &parser);
|
||||
static const Variable &referenceFromSAS(utils::Parser<> &parser, const Variables &variables);
|
||||
|
||||
public:
|
||||
void printNameAsASPPredicate(utils::LogStream &outputStream) const;
|
||||
|
@@ -26,7 +26,7 @@ using VariableTransitions = std::vector<VariableTransition>;
|
||||
class VariableTransition
|
||||
{
|
||||
public:
|
||||
static VariableTransition fromSAS(utils::Parser &parser, const Variables &variables);
|
||||
static VariableTransition fromSAS(utils::Parser<> &parser, const Variables &variables);
|
||||
|
||||
public:
|
||||
const Variable &variable() const;
|
||||
|
@@ -4,8 +4,8 @@
|
||||
#include <string>
|
||||
|
||||
#include <plasp/utils/LogStream.h>
|
||||
#include <plasp/utils/Parser.h>
|
||||
#include <plasp/utils/ParserException.h>
|
||||
#include <plasp/utils/StreamCoordinate.h>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
@@ -44,8 +44,8 @@ class Logger
|
||||
void setColorPolicy(LogStream::ColorPolicy colorPolicy);
|
||||
|
||||
void logError(const std::string &message);
|
||||
void logError(const Parser::Coordinate &coordinate, const std::string &message);
|
||||
void logWarning(const Parser &parser, const std::string &message);
|
||||
void logError(const StreamCoordinate &coordinate, const std::string &message);
|
||||
void logWarning(const StreamCoordinate &parserCoordinate, const std::string &message);
|
||||
|
||||
private:
|
||||
LogStream m_outputStream;
|
||||
|
@@ -8,111 +8,194 @@
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <plasp/utils/ParserException.h>
|
||||
#include <plasp/utils/ParserPolicy.h>
|
||||
#include <plasp/utils/Stream.h>
|
||||
#include <plasp/utils/StreamCoordinate.h>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
|
||||
template<typename Type>
|
||||
struct Tag
|
||||
{
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Parser
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class Parser
|
||||
template<class ParserPolicy = CaseSensitiveParserPolicy>
|
||||
class Parser: public Stream, public ParserPolicy
|
||||
{
|
||||
public:
|
||||
using Position = std::stringstream::pos_type;
|
||||
|
||||
struct Coordinate
|
||||
{
|
||||
std::string sectionName;
|
||||
size_t row;
|
||||
size_t column;
|
||||
};
|
||||
|
||||
struct StreamDelimiter
|
||||
{
|
||||
Position position;
|
||||
std::string sectionName;
|
||||
};
|
||||
template<class OtherParserPolicy>
|
||||
friend class Parser;
|
||||
|
||||
public:
|
||||
explicit Parser();
|
||||
explicit Parser(std::string streamName, std::istream &istream);
|
||||
|
||||
// Forbid copy construction/assignment
|
||||
Parser(const Parser &other) = delete;
|
||||
Parser &operator=(const Parser &other) = delete;
|
||||
|
||||
Parser(Parser &&other);
|
||||
Parser &operator=(Parser &&other);
|
||||
|
||||
void readStream(std::string streamName, std::istream &istream);
|
||||
void readFile(const boost::filesystem::path &path);
|
||||
|
||||
void reset();
|
||||
void seek(Position position);
|
||||
Position position() const;
|
||||
Coordinate coordinate() const;
|
||||
|
||||
void setCaseSensitive(bool isCaseInsensitive = true);
|
||||
|
||||
char currentCharacter() const;
|
||||
void advance();
|
||||
bool atEndOfStream() const;
|
||||
template<class OtherParser>
|
||||
Parser(OtherParser &&otherParser)
|
||||
{
|
||||
m_stream = std::move(otherParser.m_stream);
|
||||
m_delimiters = std::move(otherParser.m_delimiters);
|
||||
}
|
||||
|
||||
void removeComments(const std::string &startSequence, const std::string &endSequence, bool removeEnd);
|
||||
|
||||
char currentCharacter() const;
|
||||
|
||||
template<typename Type>
|
||||
Type parse();
|
||||
|
||||
template<class CharacterPredicate, class WhiteSpacePredicate>
|
||||
std::string parseIdentifier(CharacterPredicate characterPredicate, WhiteSpacePredicate whiteSpacePredicate);
|
||||
|
||||
template<class CharacterPredicate>
|
||||
std::string parseIdentifier(CharacterPredicate characterPredicate);
|
||||
template<typename Type>
|
||||
bool testAndReturn(const Type &expectedValue);
|
||||
|
||||
template<typename Type>
|
||||
bool probe(const Type &expectedValue);
|
||||
|
||||
template<class CharacterPredicate>
|
||||
bool probeIdentifier(const std::string &identifier, CharacterPredicate characterPredicate);
|
||||
|
||||
bool probeNumber();
|
||||
bool testAndSkip(const Type &expectedValue);
|
||||
|
||||
template<typename Type>
|
||||
void expect(const Type &expectedValue);
|
||||
|
||||
template<class WhiteSpacePredicate>
|
||||
void skipWhiteSpace(WhiteSpacePredicate whiteSpacePredicate);
|
||||
std::string parseIdentifier();
|
||||
bool testIdentifierAndReturn(const std::string &identifier);
|
||||
bool testIdentifierAndSkip(const std::string &identifier);
|
||||
|
||||
// TODO: remove
|
||||
bool probeNumber();
|
||||
|
||||
std::string parseLine();
|
||||
|
||||
void skipWhiteSpace();
|
||||
void skipLine();
|
||||
|
||||
std::string getLine();
|
||||
|
||||
private:
|
||||
static const std::istreambuf_iterator<char> EndOfFile;
|
||||
std::string parseImpl(Tag<std::string>);
|
||||
char parseImpl(Tag<char>);
|
||||
uint64_t parseImpl(Tag<uint64_t>);
|
||||
int64_t parseImpl(Tag<int64_t>);
|
||||
uint32_t parseImpl(Tag<uint32_t>);
|
||||
int32_t parseImpl(Tag<int32_t>);
|
||||
bool parseImpl(Tag<bool>);
|
||||
|
||||
private:
|
||||
void checkStream() const;
|
||||
bool testImpl(const std::string &expectedValue);
|
||||
bool testImpl(char expectedValue);
|
||||
bool testImpl(uint64_t expectedValue);
|
||||
bool testImpl(int64_t expectedValue);
|
||||
bool testImpl(uint32_t expectedValue);
|
||||
bool testImpl(int32_t expectedValue);
|
||||
bool testImpl(bool expectedValue);
|
||||
|
||||
uint64_t parseIntegerBody();
|
||||
|
||||
mutable std::stringstream m_stream;
|
||||
|
||||
std::vector<StreamDelimiter> m_streamDelimiters;
|
||||
|
||||
bool m_isCaseSensitive;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class CharacterPredicate, class WhiteSpacePredicate>
|
||||
std::string Parser::parseIdentifier(CharacterPredicate characterPredicate, WhiteSpacePredicate whiteSpacePredicate)
|
||||
template<class ParserPolicy>
|
||||
Parser<ParserPolicy>::Parser()
|
||||
: Stream()
|
||||
{
|
||||
skipWhiteSpace(whiteSpacePredicate);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
Parser<ParserPolicy>::Parser(std::string streamName, std::istream &istream)
|
||||
: Stream(streamName, istream)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
void Parser<ParserPolicy>::skipWhiteSpace()
|
||||
{
|
||||
check();
|
||||
|
||||
while (!atEnd() && ParserPolicy::isWhiteSpaceCharacter(currentCharacter()))
|
||||
advance();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
void Parser<ParserPolicy>::skipLine()
|
||||
{
|
||||
check();
|
||||
|
||||
while (currentCharacter() != '\n')
|
||||
advance();
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
template<typename Type>
|
||||
Type Parser<ParserPolicy>::parse()
|
||||
{
|
||||
return parseImpl(Tag<Type>());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
template<typename Type>
|
||||
bool Parser<ParserPolicy>::testAndReturn(const Type &expectedValue)
|
||||
{
|
||||
const auto previousPosition = position();
|
||||
|
||||
const auto result = testImpl(expectedValue);
|
||||
|
||||
seek(previousPosition);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
template<typename Type>
|
||||
bool Parser<ParserPolicy>::testAndSkip(const Type &expectedValue)
|
||||
{
|
||||
const auto previousPosition = position();
|
||||
|
||||
const auto result = testImpl(expectedValue);
|
||||
|
||||
if (result == false)
|
||||
seek(previousPosition);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
template<typename Type>
|
||||
void Parser<ParserPolicy>::expect(const Type &expectedValue)
|
||||
{
|
||||
if (testAndSkip(expectedValue))
|
||||
return;
|
||||
|
||||
std::stringstream message;
|
||||
message << "unexpected value, expected “" << expectedValue << "”";
|
||||
|
||||
throw ParserException(coordinate(), message.str());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
std::string Parser<ParserPolicy>::parseIdentifier()
|
||||
{
|
||||
skipWhiteSpace();
|
||||
|
||||
std::string value;
|
||||
|
||||
@@ -120,7 +203,7 @@ std::string Parser::parseIdentifier(CharacterPredicate characterPredicate, White
|
||||
{
|
||||
const auto character = currentCharacter();
|
||||
|
||||
if (!characterPredicate(character))
|
||||
if (!ParserPolicy::isIdentifierCharacter(character))
|
||||
return value;
|
||||
|
||||
value.push_back(character);
|
||||
@@ -130,33 +213,342 @@ std::string Parser::parseIdentifier(CharacterPredicate characterPredicate, White
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class CharacterPredicate>
|
||||
std::string Parser::parseIdentifier(CharacterPredicate characterPredicate)
|
||||
template<class ParserPolicy>
|
||||
bool Parser<ParserPolicy>::testIdentifierAndSkip(const std::string &expectedValue)
|
||||
{
|
||||
return parseIdentifier(characterPredicate,
|
||||
[&](const auto character)
|
||||
{
|
||||
return std::isspace(character);
|
||||
});
|
||||
return testAndSkip(expectedValue) && !ParserPolicy::isIdentifierCharacter(currentCharacter());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class CharacterPredicate>
|
||||
bool Parser::probeIdentifier(const std::string &expectedValue, CharacterPredicate characterPredicate)
|
||||
template<class ParserPolicy>
|
||||
bool Parser<ParserPolicy>::probeNumber()
|
||||
{
|
||||
return probe<std::string>(expectedValue) && !characterPredicate(currentCharacter());
|
||||
const auto previousPosition = position();
|
||||
|
||||
skipWhiteSpace();
|
||||
|
||||
while (!ParserPolicy::isWhiteSpaceCharacter(currentCharacter()))
|
||||
if (!std::isdigit(currentCharacter()))
|
||||
{
|
||||
seek(previousPosition);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class WhiteSpacePredicate>
|
||||
void Parser::skipWhiteSpace(WhiteSpacePredicate whiteSpacePredicate)
|
||||
template<class ParserPolicy>
|
||||
std::string Parser<ParserPolicy>::parseLine()
|
||||
{
|
||||
checkStream();
|
||||
std::string value;
|
||||
|
||||
while (!atEndOfStream() && whiteSpacePredicate(currentCharacter()))
|
||||
while (true)
|
||||
{
|
||||
const auto character = currentCharacter();
|
||||
advance();
|
||||
|
||||
if (character == '\n')
|
||||
break;
|
||||
else if (character == '\r')
|
||||
continue;
|
||||
|
||||
value.push_back(character);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
void Parser<ParserPolicy>::removeComments(const std::string &startSequence, const std::string &endSequence, bool removeEnd)
|
||||
{
|
||||
const auto inPosition = m_stream.tellg();
|
||||
const auto outPosition = m_stream.tellp();
|
||||
|
||||
m_stream.seekg(0);
|
||||
|
||||
const auto removeRange =
|
||||
[&](const auto &start, const auto &end)
|
||||
{
|
||||
BOOST_ASSERT(start != -1);
|
||||
|
||||
m_stream.clear();
|
||||
m_stream.seekp(start);
|
||||
m_stream.seekg(start);
|
||||
|
||||
auto position = start;
|
||||
|
||||
while (end == -1 || position < end)
|
||||
{
|
||||
m_stream.ignore(1);
|
||||
|
||||
if (atEnd())
|
||||
return;
|
||||
|
||||
m_stream.put(' ');
|
||||
position += static_cast<std::streamoff>(1);
|
||||
}
|
||||
};
|
||||
|
||||
while (!atEnd())
|
||||
{
|
||||
Position startPosition = m_stream.tellg();
|
||||
|
||||
while (!atEnd())
|
||||
{
|
||||
startPosition = m_stream.tellg();
|
||||
|
||||
if (testAndSkip(startSequence))
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
Position endPosition = m_stream.tellg();
|
||||
|
||||
while (!atEnd())
|
||||
{
|
||||
endPosition = m_stream.tellg();
|
||||
|
||||
if (testAndSkip(endSequence))
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (removeEnd)
|
||||
endPosition = m_stream.tellg();
|
||||
|
||||
removeRange(startPosition, endPosition);
|
||||
}
|
||||
|
||||
m_stream.clear();
|
||||
|
||||
m_stream.seekg(inPosition);
|
||||
m_stream.seekp(outPosition);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
char Parser<ParserPolicy>::currentCharacter() const
|
||||
{
|
||||
return ParserPolicy::transformCharacter(Stream::currentCharacter());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
std::string Parser<ParserPolicy>::parseImpl(Tag<std::string>)
|
||||
{
|
||||
skipWhiteSpace();
|
||||
|
||||
const auto startPosition = position();
|
||||
|
||||
while (!ParserPolicy::isWhiteSpaceCharacter(currentCharacter()))
|
||||
advance();
|
||||
|
||||
const auto endPosition = position();
|
||||
const auto length = static_cast<size_t>(endPosition - startPosition);
|
||||
|
||||
std::string value;
|
||||
value.reserve(length);
|
||||
|
||||
seek(startPosition);
|
||||
|
||||
for (size_t i = 0; i < length; i++)
|
||||
{
|
||||
value.push_back(currentCharacter());
|
||||
advance();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
char Parser<ParserPolicy>::parseImpl(Tag<char>)
|
||||
{
|
||||
const auto value = currentCharacter();
|
||||
|
||||
advance();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
uint64_t Parser<ParserPolicy>::parseIntegerBody()
|
||||
{
|
||||
check();
|
||||
|
||||
if (!std::isdigit(currentCharacter()))
|
||||
throw ParserException(coordinate(), "could not parse integer value");
|
||||
|
||||
uint64_t value = 0;
|
||||
|
||||
while (!atEnd())
|
||||
{
|
||||
const auto character = currentCharacter();
|
||||
|
||||
if (!std::isdigit(character))
|
||||
break;
|
||||
|
||||
value *= 10;
|
||||
value += character - '0';
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
int64_t Parser<ParserPolicy>::parseImpl(Tag<int64_t>)
|
||||
{
|
||||
skipWhiteSpace();
|
||||
|
||||
bool positive = testAndSkip<char>('+') || !testAndSkip<char>('-');
|
||||
|
||||
const auto value = parseIntegerBody();
|
||||
|
||||
return (positive ? value : -value);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
uint64_t Parser<ParserPolicy>::parseImpl(Tag<uint64_t>)
|
||||
{
|
||||
skipWhiteSpace();
|
||||
|
||||
if (currentCharacter() == '-')
|
||||
throw ParserException(coordinate(), "expected unsigned integer, got signed one");
|
||||
|
||||
return parseIntegerBody();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
int32_t Parser<ParserPolicy>::parseImpl(Tag<int32_t>)
|
||||
{
|
||||
return static_cast<int32_t>(parseImpl(Tag<int64_t>()));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
uint32_t Parser<ParserPolicy>::parseImpl(Tag<uint32_t>)
|
||||
{
|
||||
return static_cast<uint32_t>(parseImpl(Tag<uint64_t>()));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
bool Parser<ParserPolicy>::parseImpl(Tag<bool>)
|
||||
{
|
||||
skipWhiteSpace();
|
||||
|
||||
if (testAndSkip<char>('0'))
|
||||
return false;
|
||||
|
||||
if (testAndSkip<char>('1'))
|
||||
return true;
|
||||
|
||||
throw ParserException(coordinate(), "could not parse Boolean value");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
bool Parser<ParserPolicy>::testImpl(const std::string &expectedValue)
|
||||
{
|
||||
if (!ParserPolicy::isWhiteSpaceCharacter(expectedValue.front()))
|
||||
skipWhiteSpace();
|
||||
|
||||
const auto match = std::find_if(expectedValue.cbegin(), expectedValue.cend(),
|
||||
[&](const auto &expectedCharacter)
|
||||
{
|
||||
const auto character = static_cast<char>(this->currentCharacter());
|
||||
|
||||
if (character != expectedCharacter)
|
||||
return true;
|
||||
|
||||
this->advance();
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return (match == expectedValue.cend());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
bool Parser<ParserPolicy>::testImpl(char expectedValue)
|
||||
{
|
||||
const auto result = (currentCharacter() == expectedValue);
|
||||
|
||||
advance();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
bool Parser<ParserPolicy>::testImpl(int64_t expectedValue)
|
||||
{
|
||||
const auto value = parseImpl(Tag<int64_t>());
|
||||
|
||||
return (value == expectedValue);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
bool Parser<ParserPolicy>::testImpl(uint64_t expectedValue)
|
||||
{
|
||||
const auto value = parseImpl(Tag<uint64_t>());
|
||||
|
||||
return (value == expectedValue);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
bool Parser<ParserPolicy>::testImpl(int32_t expectedValue)
|
||||
{
|
||||
return testImpl(static_cast<int64_t>(expectedValue));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
bool Parser<ParserPolicy>::testImpl(uint32_t expectedValue)
|
||||
{
|
||||
return testImpl(static_cast<uint64_t>(expectedValue));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class ParserPolicy>
|
||||
bool Parser<ParserPolicy>::testImpl(bool expectedValue)
|
||||
{
|
||||
const auto value = parseImpl(Tag<bool>());
|
||||
|
||||
return (value == expectedValue);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@@ -4,7 +4,7 @@
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
#include <plasp/utils/Parser.h>
|
||||
#include <plasp/utils/StreamCoordinate.h>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
@@ -20,18 +20,18 @@ namespace utils
|
||||
class ParserException: public std::exception
|
||||
{
|
||||
public:
|
||||
explicit ParserException(const utils::Parser &parser)
|
||||
: ParserException(parser, "unspecified parser error")
|
||||
explicit ParserException(const StreamCoordinate &coordinate)
|
||||
: ParserException(coordinate, "unspecified parser error")
|
||||
{
|
||||
}
|
||||
|
||||
explicit ParserException(const utils::Parser &parser, const char *message)
|
||||
: ParserException(parser, static_cast<std::string>(message))
|
||||
explicit ParserException(const StreamCoordinate &coordinate, const char *message)
|
||||
: ParserException(coordinate, static_cast<std::string>(message))
|
||||
{
|
||||
}
|
||||
|
||||
explicit ParserException(const utils::Parser &parser, const std::string &message)
|
||||
: m_coordinate{parser.coordinate()},
|
||||
explicit ParserException(const StreamCoordinate &coordinate, const std::string &message)
|
||||
: m_coordinate{coordinate},
|
||||
m_message{message},
|
||||
m_plainMessage{m_coordinate.sectionName + ":" + std::to_string(m_coordinate.row)
|
||||
+ ":" + std::to_string(m_coordinate.column) + " " + m_message}
|
||||
@@ -47,7 +47,7 @@ class ParserException: public std::exception
|
||||
return m_plainMessage.c_str();
|
||||
}
|
||||
|
||||
const Parser::Coordinate &coordinate() const
|
||||
const StreamCoordinate &coordinate() const
|
||||
{
|
||||
return m_coordinate;
|
||||
}
|
||||
@@ -58,7 +58,7 @@ class ParserException: public std::exception
|
||||
}
|
||||
|
||||
private:
|
||||
Parser::Coordinate m_coordinate;
|
||||
StreamCoordinate m_coordinate;
|
||||
std::string m_message;
|
||||
std::string m_plainMessage;
|
||||
};
|
||||
|
62
include/plasp/utils/ParserPolicy.h
Normal file
62
include/plasp/utils/ParserPolicy.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef __PLASP__UTILS__PARSER_POLICY_H
|
||||
#define __PLASP__UTILS__PARSER_POLICY_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ParserPolicy
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CaseSensitiveParserPolicy
|
||||
{
|
||||
public:
|
||||
static constexpr char transformCharacter(char c) noexcept
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
static bool isWhiteSpaceCharacter(char c)
|
||||
{
|
||||
return std::iswspace(c);
|
||||
}
|
||||
|
||||
static bool isIdentifierCharacter(char c)
|
||||
{
|
||||
return std::isgraph(c);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CaseInsensitiveParserPolicy
|
||||
{
|
||||
public:
|
||||
static char transformCharacter(char c) noexcept
|
||||
{
|
||||
return std::tolower(c);
|
||||
}
|
||||
|
||||
static bool isWhiteSpaceCharacter(char c)
|
||||
{
|
||||
return std::iswspace(c);
|
||||
}
|
||||
|
||||
static bool isIdentifierCharacter(char c)
|
||||
{
|
||||
return std::isgraph(c);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
84
include/plasp/utils/Stream.h
Normal file
84
include/plasp/utils/Stream.h
Normal file
@@ -0,0 +1,84 @@
|
||||
#ifndef __PLASP__UTILS__STREAM_H
|
||||
#define __PLASP__UTILS__STREAM_H
|
||||
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <plasp/utils/ParserException.h>
|
||||
#include <plasp/utils/StreamCoordinate.h>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Stream
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class Stream
|
||||
{
|
||||
public:
|
||||
using Position = std::stringstream::pos_type;
|
||||
|
||||
struct Delimiter
|
||||
{
|
||||
Position position;
|
||||
std::string sectionName;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit Stream();
|
||||
explicit Stream(std::string streamName, std::istream &istream);
|
||||
|
||||
Stream(const Stream &other) = delete;
|
||||
Stream &operator=(const Stream &other) = delete;
|
||||
|
||||
Stream(Stream &&other)
|
||||
: m_stream{std::move(other.m_stream)},
|
||||
m_delimiters{std::move(other.m_delimiters)}
|
||||
{
|
||||
}
|
||||
|
||||
Stream &operator=(Stream &&other)
|
||||
{
|
||||
m_stream = std::move(other.m_stream);
|
||||
m_delimiters = std::move(other.m_delimiters);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Stream() = default;
|
||||
|
||||
void read(std::string streamName, std::istream &istream);
|
||||
void read(const boost::filesystem::path &path);
|
||||
|
||||
void reset();
|
||||
void seek(Position position);
|
||||
Position position() const;
|
||||
StreamCoordinate coordinate() const;
|
||||
|
||||
char currentCharacter() const;
|
||||
void advance();
|
||||
bool atEnd() const;
|
||||
|
||||
void check() const;
|
||||
|
||||
protected:
|
||||
mutable std::stringstream m_stream;
|
||||
|
||||
std::vector<Delimiter> m_delimiters;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,27 +1,24 @@
|
||||
#ifndef __PLASP__PDDL__IDENTIFIER_H
|
||||
#define __PLASP__PDDL__IDENTIFIER_H
|
||||
#ifndef __PLASP__UTILS__STREAM_COORDINATE_H
|
||||
#define __PLASP__UTILS__STREAM_COORDINATE_H
|
||||
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
namespace pddl
|
||||
namespace utils
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Identifier
|
||||
// StreamCoordinate
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const auto isIdentifier =
|
||||
[](const auto character)
|
||||
struct StreamCoordinate
|
||||
{
|
||||
return character != '?'
|
||||
&& character != '('
|
||||
&& character != ')'
|
||||
&& character != ';'
|
||||
&& std::isgraph(character);
|
||||
std::string sectionName;
|
||||
size_t row;
|
||||
size_t column;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
@@ -5,10 +5,8 @@
|
||||
#include <plasp/pddl/Context.h>
|
||||
#include <plasp/pddl/Domain.h>
|
||||
#include <plasp/pddl/ExpressionContext.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/pddl/expressions/Type.h>
|
||||
#include <plasp/utils/IO.h>
|
||||
#include <plasp/utils/ParserException.h>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
@@ -23,31 +21,33 @@ namespace pddl
|
||||
|
||||
void Action::parseDeclaration(Context &context, Domain &domain)
|
||||
{
|
||||
auto &parser = context.parser;
|
||||
|
||||
auto action = std::make_unique<Action>(Action());
|
||||
|
||||
action->m_name = context.parser.parseIdentifier(isIdentifier);
|
||||
action->m_name = parser.parseIdentifier();
|
||||
|
||||
context.parser.expect<std::string>(":parameters");
|
||||
context.parser.expect<std::string>("(");
|
||||
parser.expect<std::string>(":parameters");
|
||||
parser.expect<std::string>("(");
|
||||
|
||||
ExpressionContext expressionContext(domain, action->m_parameters);
|
||||
|
||||
// Read parameters
|
||||
expressions::Variable::parseTypedDeclarations(context, expressionContext);
|
||||
|
||||
context.parser.expect<std::string>(")");
|
||||
parser.expect<std::string>(")");
|
||||
|
||||
// Parse preconditions and effects
|
||||
while (context.parser.currentCharacter() != ')')
|
||||
while (!parser.testAndReturn(')'))
|
||||
{
|
||||
context.parser.expect<std::string>(":");
|
||||
parser.expect<std::string>(":");
|
||||
|
||||
if (context.parser.probeIdentifier("precondition", isIdentifier))
|
||||
if (parser.testIdentifierAndSkip("precondition"))
|
||||
action->m_precondition = parsePreconditionExpression(context, expressionContext);
|
||||
else if (context.parser.probeIdentifier("effect", isIdentifier))
|
||||
else if (parser.testIdentifierAndSkip("effect"))
|
||||
action->m_effect = parseEffectExpression(context, expressionContext);
|
||||
|
||||
context.parser.skipWhiteSpace();
|
||||
parser.skipWhiteSpace();
|
||||
}
|
||||
|
||||
// Store new action
|
||||
|
@@ -44,7 +44,7 @@ Description Description::fromStream(std::istream &istream)
|
||||
{
|
||||
Description description;
|
||||
|
||||
description.m_context.parser.readStream("std::cin", istream);
|
||||
description.m_context.parser.read("std::cin", istream);
|
||||
description.parse();
|
||||
|
||||
return description;
|
||||
@@ -56,7 +56,7 @@ Description Description::fromFile(const std::string &path)
|
||||
{
|
||||
Description description;
|
||||
|
||||
description.m_context.parser.readFile(path);
|
||||
description.m_context.parser.read(path);
|
||||
description.parse();
|
||||
|
||||
return description;
|
||||
@@ -73,7 +73,7 @@ Description Description::fromFiles(const std::vector<std::string> &paths)
|
||||
std::for_each(paths.cbegin(), paths.cend(),
|
||||
[&](const auto &path)
|
||||
{
|
||||
description.m_context.parser.readFile(path);
|
||||
description.m_context.parser.read(path);
|
||||
});
|
||||
|
||||
description.parse();
|
||||
@@ -126,7 +126,6 @@ void Description::parse()
|
||||
{
|
||||
auto &parser = m_context.parser;
|
||||
|
||||
parser.setCaseSensitive(false);
|
||||
parser.removeComments(";", "\n", false);
|
||||
|
||||
// First, determine the locations of domain and problem
|
||||
@@ -155,7 +154,7 @@ void Description::findSections()
|
||||
|
||||
parser.skipWhiteSpace();
|
||||
|
||||
while (!parser.atEndOfStream())
|
||||
while (!parser.atEnd())
|
||||
{
|
||||
const auto position = parser.position();
|
||||
|
||||
@@ -163,20 +162,20 @@ void Description::findSections()
|
||||
parser.expect<std::string>("define");
|
||||
parser.expect<std::string>("(");
|
||||
|
||||
if (parser.probe<std::string>("domain"))
|
||||
if (parser.testAndSkip<std::string>("domain"))
|
||||
{
|
||||
if (m_domainPosition != -1)
|
||||
throw utils::ParserException(parser, "PDDL description may not contain two domains");
|
||||
throw utils::ParserException(parser.coordinate(), "PDDL description may not contain two domains");
|
||||
|
||||
m_domainPosition = position;
|
||||
|
||||
parser.seek(position);
|
||||
m_domain->findSections();
|
||||
}
|
||||
else if (m_context.parser.probe<std::string>("problem"))
|
||||
else if (m_context.parser.testAndSkip<std::string>("problem"))
|
||||
{
|
||||
if (m_problemPosition != -1)
|
||||
throw utils::ParserException(parser, "PDDL description may currently not contain two problems");
|
||||
throw utils::ParserException(parser.coordinate(), "PDDL description may currently not contain two problems");
|
||||
|
||||
m_problem = std::make_unique<Problem>(Problem(m_context, *m_domain));
|
||||
|
||||
@@ -188,7 +187,7 @@ void Description::findSections()
|
||||
else
|
||||
{
|
||||
const auto sectionIdentifier = parser.parse<std::string>();
|
||||
throw utils::ParserException(parser, "unknown PDDL section “" + sectionIdentifier + "”");
|
||||
throw utils::ParserException(parser.coordinate(), "unknown PDDL section “" + sectionIdentifier + "”");
|
||||
}
|
||||
|
||||
m_context.parser.skipWhiteSpace();
|
||||
|
@@ -3,7 +3,6 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <plasp/pddl/ConsistencyException.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/pddl/IO.h>
|
||||
#include <plasp/pddl/expressions/Constant.h>
|
||||
#include <plasp/pddl/expressions/PredicateDeclaration.h>
|
||||
@@ -43,7 +42,7 @@ void Domain::findSections()
|
||||
parser.expect<std::string>("(");
|
||||
parser.expect<std::string>("domain");
|
||||
|
||||
m_name = m_context.parser.parseIdentifier(isIdentifier);
|
||||
m_name = m_context.parser.parseIdentifier();
|
||||
|
||||
parser.expect<std::string>(")");
|
||||
|
||||
@@ -53,7 +52,7 @@ void Domain::findSections()
|
||||
if (unique && sectionPosition != -1)
|
||||
{
|
||||
parser.seek(value);
|
||||
throw utils::ParserException(parser, "only one “:" + sectionName + "” section allowed");
|
||||
throw utils::ParserException(parser.coordinate(), "only one “:" + sectionName + "” section allowed");
|
||||
}
|
||||
|
||||
sectionPosition = value;
|
||||
@@ -72,38 +71,38 @@ void Domain::findSections()
|
||||
const auto sectionIdentifierPosition = parser.position();
|
||||
|
||||
// Save the parser position of the individual sections for later parsing
|
||||
if (parser.probeIdentifier("requirements", isIdentifier))
|
||||
if (parser.testIdentifierAndSkip("requirements"))
|
||||
setSectionPosition("requirements", m_requirementsPosition, position, true);
|
||||
else if (parser.probeIdentifier("types", isIdentifier))
|
||||
else if (parser.testIdentifierAndSkip("types"))
|
||||
setSectionPosition("types", m_typesPosition, position, true);
|
||||
else if (parser.probeIdentifier("constants", isIdentifier))
|
||||
else if (parser.testIdentifierAndSkip("constants"))
|
||||
setSectionPosition("constants", m_constantsPosition, position, true);
|
||||
else if (parser.probeIdentifier("predicates", isIdentifier))
|
||||
else if (parser.testIdentifierAndSkip("predicates"))
|
||||
setSectionPosition("predicates", m_predicatesPosition, position, true);
|
||||
else if (parser.probeIdentifier("action", isIdentifier))
|
||||
else if (parser.testIdentifierAndSkip("action"))
|
||||
{
|
||||
m_actionPositions.emplace_back(-1);
|
||||
setSectionPosition("action", m_actionPositions.back(), position);
|
||||
}
|
||||
else if (parser.probeIdentifier("functions", isIdentifier)
|
||||
|| parser.probeIdentifier("constraints", isIdentifier)
|
||||
|| parser.probeIdentifier("durative-action", isIdentifier)
|
||||
|| parser.probeIdentifier("derived", isIdentifier))
|
||||
else if (parser.testIdentifierAndSkip("functions")
|
||||
|| parser.testIdentifierAndSkip("constraints")
|
||||
|| parser.testIdentifierAndSkip("durative-action")
|
||||
|| parser.testIdentifierAndSkip("derived"))
|
||||
{
|
||||
parser.seek(sectionIdentifierPosition);
|
||||
|
||||
const auto sectionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto sectionIdentifier = parser.parseIdentifier();
|
||||
|
||||
m_context.logger.logWarning(parser, "section type “" + sectionIdentifier + "” currently unsupported");
|
||||
m_context.logger.logWarning(parser.coordinate(), "section type “" + sectionIdentifier + "” currently unsupported");
|
||||
|
||||
parser.seek(sectionIdentifierPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto sectionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto sectionIdentifier = parser.parseIdentifier();
|
||||
|
||||
parser.seek(position);
|
||||
throw utils::ParserException(m_context.parser, "unknown domain section “" + sectionIdentifier + "”");
|
||||
throw utils::ParserException(parser.coordinate(), "unknown domain section “" + sectionIdentifier + "”");
|
||||
}
|
||||
|
||||
// Skip section for now and parse it later
|
||||
@@ -340,7 +339,7 @@ void Domain::parseTypeSection()
|
||||
while (parser.currentCharacter() != ')')
|
||||
{
|
||||
if (parser.currentCharacter() == '(')
|
||||
throw utils::ParserException(parser, "only primitive types are allowed in type section");
|
||||
throw utils::ParserException(parser.coordinate(), "only primitive types are allowed in type section");
|
||||
|
||||
expressions::PrimitiveType::parseTypedDeclaration(m_context, *this);
|
||||
|
||||
|
@@ -3,7 +3,6 @@
|
||||
#include <plasp/pddl/Context.h>
|
||||
#include <plasp/pddl/Domain.h>
|
||||
#include <plasp/pddl/ExpressionContext.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/pddl/IO.h>
|
||||
#include <plasp/pddl/expressions/And.h>
|
||||
#include <plasp/pddl/expressions/Imply.h>
|
||||
@@ -49,12 +48,12 @@ ExpressionPointer parsePreconditionExpression(Context &context,
|
||||
|
||||
const auto expressionIdentifierPosition = parser.position();
|
||||
|
||||
if (parser.probeIdentifier("forall", isIdentifier)
|
||||
|| parser.probeIdentifier("preference", isIdentifier))
|
||||
if (parser.testIdentifierAndSkip("forall")
|
||||
|| parser.testIdentifierAndSkip("preference"))
|
||||
{
|
||||
// TODO: refactor
|
||||
parser.seek(expressionIdentifierPosition);
|
||||
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto expressionIdentifier = parser.parseIdentifier();
|
||||
|
||||
parser.seek(position);
|
||||
return expressions::Unsupported::parse(context);
|
||||
@@ -89,32 +88,32 @@ ExpressionPointer parseExpression(Context &context, ExpressionContext &expressio
|
||||
|
||||
const auto expressionIdentifierPosition = parser.position();
|
||||
|
||||
if (parser.probeIdentifier("exists", isIdentifier)
|
||||
|| parser.probeIdentifier("forall", isIdentifier)
|
||||
|| parser.probeIdentifier("-", isIdentifier)
|
||||
|| parser.probeIdentifier("=", isIdentifier)
|
||||
|| parser.probeIdentifier("*", isIdentifier)
|
||||
|| parser.probeIdentifier("+", isIdentifier)
|
||||
|| parser.probeIdentifier("-", isIdentifier)
|
||||
|| parser.probeIdentifier("/", isIdentifier)
|
||||
|| parser.probeIdentifier(">", isIdentifier)
|
||||
|| parser.probeIdentifier("<", isIdentifier)
|
||||
|| parser.probeIdentifier("=", isIdentifier)
|
||||
|| parser.probeIdentifier(">=", isIdentifier)
|
||||
|| parser.probeIdentifier("<=", isIdentifier))
|
||||
if (parser.testIdentifierAndSkip("exists")
|
||||
|| parser.testIdentifierAndSkip("forall")
|
||||
|| parser.testIdentifierAndSkip("-")
|
||||
|| parser.testIdentifierAndSkip("=")
|
||||
|| parser.testIdentifierAndSkip("*")
|
||||
|| parser.testIdentifierAndSkip("+")
|
||||
|| parser.testIdentifierAndSkip("-")
|
||||
|| parser.testIdentifierAndSkip("/")
|
||||
|| parser.testIdentifierAndSkip(">")
|
||||
|| parser.testIdentifierAndSkip("<")
|
||||
|| parser.testIdentifierAndSkip("=")
|
||||
|| parser.testIdentifierAndSkip(">=")
|
||||
|| parser.testIdentifierAndSkip("<="))
|
||||
{
|
||||
parser.seek(expressionIdentifierPosition);
|
||||
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto expressionIdentifier = parser.parseIdentifier();
|
||||
|
||||
parser.seek(position);
|
||||
return expressions::Unsupported::parse(context);
|
||||
}
|
||||
|
||||
parser.seek(expressionIdentifierPosition);
|
||||
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto expressionIdentifier = parser.parseIdentifier();
|
||||
|
||||
parser.seek(position);
|
||||
throw utils::ParserException(context.parser, "expression type “" + expressionIdentifier + "” unknown or not allowed in this context");
|
||||
throw utils::ParserException(parser.coordinate(), "expression type “" + expressionIdentifier + "” unknown or not allowed in this context");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -134,11 +133,11 @@ ExpressionPointer parseEffectExpression(Context &context, ExpressionContext &exp
|
||||
|
||||
const auto expressionIdentifierPosition = parser.position();
|
||||
|
||||
if (parser.probeIdentifier("forall", isIdentifier)
|
||||
|| parser.probeIdentifier("when", isIdentifier))
|
||||
if (parser.testIdentifierAndSkip("forall")
|
||||
|| parser.testIdentifierAndSkip("when"))
|
||||
{
|
||||
parser.seek(expressionIdentifierPosition);
|
||||
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto expressionIdentifier = parser.parseIdentifier();
|
||||
|
||||
parser.seek(position);
|
||||
return expressions::Unsupported::parse(context);
|
||||
@@ -168,37 +167,39 @@ ExpressionPointer parseEffectBodyExpression(Context &context, ExpressionContext
|
||||
|
||||
const auto expressionIdentifierPosition = parser.position();
|
||||
|
||||
if (parser.probeIdentifier("=", isIdentifier)
|
||||
|| parser.probeIdentifier("assign", isIdentifier)
|
||||
|| parser.probeIdentifier("scale-up", isIdentifier)
|
||||
|| parser.probeIdentifier("scale-down", isIdentifier)
|
||||
|| parser.probeIdentifier("increase", isIdentifier)
|
||||
|| parser.probeIdentifier("decrease", isIdentifier))
|
||||
if (parser.testIdentifierAndSkip("=")
|
||||
|| parser.testIdentifierAndSkip("assign")
|
||||
|| parser.testIdentifierAndSkip("scale-up")
|
||||
|| parser.testIdentifierAndSkip("scale-down")
|
||||
|| parser.testIdentifierAndSkip("increase")
|
||||
|| parser.testIdentifierAndSkip("decrease"))
|
||||
{
|
||||
parser.seek(expressionIdentifierPosition);
|
||||
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto expressionIdentifier = parser.parseIdentifier();
|
||||
|
||||
parser.seek(position);
|
||||
return expressions::Unsupported::parse(context);
|
||||
}
|
||||
|
||||
parser.seek(expressionIdentifierPosition);
|
||||
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto expressionIdentifier = parser.parseIdentifier();
|
||||
|
||||
parser.seek(position);
|
||||
throw utils::ParserException(context.parser, "expression type “" + expressionIdentifier + "” unknown or not allowed in this context");
|
||||
throw utils::ParserException(parser.coordinate(), "expression type “" + expressionIdentifier + "” unknown or not allowed in this context");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExpressionPointer parsePredicate(Context &context, ExpressionContext &expressionContext)
|
||||
{
|
||||
auto &parser = context.parser;
|
||||
|
||||
ExpressionPointer expression;
|
||||
|
||||
if ((expression = expressions::Predicate::parse(context, expressionContext)))
|
||||
return expression;
|
||||
|
||||
throw utils::ParserException(context.parser, "expected predicate");
|
||||
throw utils::ParserException(parser.coordinate(), "expected predicate");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -229,15 +230,15 @@ ExpressionPointer parseAtomicFormula(Context &context, ExpressionContext &expres
|
||||
|
||||
const auto position = parser.position();
|
||||
|
||||
if (!parser.probe<std::string>("("))
|
||||
if (!parser.testAndSkip<std::string>("("))
|
||||
return nullptr;
|
||||
|
||||
const auto expressionIdentifierPosition = parser.position();
|
||||
|
||||
if (parser.probeIdentifier("=", isIdentifier))
|
||||
if (parser.testIdentifierAndSkip("="))
|
||||
{
|
||||
parser.seek(expressionIdentifierPosition);
|
||||
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto expressionIdentifier = parser.parseIdentifier();
|
||||
|
||||
parser.seek(position);
|
||||
return expressions::Unsupported::parse(context);
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <plasp/pddl/Context.h>
|
||||
#include <plasp/pddl/ExpressionContext.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/pddl/IO.h>
|
||||
#include <plasp/pddl/Problem.h>
|
||||
#include <plasp/pddl/expressions/At.h>
|
||||
@@ -46,20 +45,20 @@ std::unique_ptr<InitialState> InitialState::parseDeclaration(Context &context,
|
||||
|
||||
const auto expressionIdentifierPosition = parser.position();
|
||||
|
||||
if (parser.probeIdentifier("=", isIdentifier))
|
||||
if (parser.testIdentifierAndSkip("="))
|
||||
{
|
||||
parser.seek(expressionIdentifierPosition);
|
||||
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto expressionIdentifier = parser.parseIdentifier();
|
||||
|
||||
parser.seek(position);
|
||||
return expressions::Unsupported::parse(context);
|
||||
}
|
||||
|
||||
parser.seek(expressionIdentifierPosition);
|
||||
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto expressionIdentifier = parser.parseIdentifier();
|
||||
|
||||
parser.seek(position);
|
||||
throw utils::ParserException(parser, "expression type “" + expressionIdentifier + "” unknown or not allowed in this context");
|
||||
throw utils::ParserException(parser.coordinate(), "expression type “" + expressionIdentifier + "” unknown or not allowed in this context");
|
||||
};
|
||||
|
||||
parser.skipWhiteSpace();
|
||||
|
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <plasp/pddl/Domain.h>
|
||||
#include <plasp/pddl/ExpressionContext.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/pddl/IO.h>
|
||||
#include <plasp/pddl/expressions/Constant.h>
|
||||
#include <plasp/utils/IO.h>
|
||||
@@ -43,7 +42,7 @@ void Problem::findSections()
|
||||
parser.expect<std::string>("(");
|
||||
parser.expect<std::string>("problem");
|
||||
|
||||
m_name = parser.parseIdentifier(isIdentifier);
|
||||
m_name = parser.parseIdentifier();
|
||||
|
||||
parser.expect<std::string>(")");
|
||||
|
||||
@@ -53,7 +52,7 @@ void Problem::findSections()
|
||||
if (unique && sectionPosition != -1)
|
||||
{
|
||||
parser.seek(value);
|
||||
throw utils::ParserException(parser, "only one “:" + sectionName + "” section allowed");
|
||||
throw utils::ParserException(parser.coordinate(), "only one “:" + sectionName + "” section allowed");
|
||||
}
|
||||
|
||||
sectionPosition = value;
|
||||
@@ -71,34 +70,34 @@ void Problem::findSections()
|
||||
const auto sectionIdentifierPosition = parser.position();
|
||||
|
||||
// TODO: check order of the sections
|
||||
if (parser.probeIdentifier("domain", isIdentifier))
|
||||
if (parser.testIdentifierAndSkip("domain"))
|
||||
setSectionPosition("domain", m_domainPosition, position, true);
|
||||
else if (parser.probeIdentifier("requirements", isIdentifier))
|
||||
else if (parser.testIdentifierAndSkip("requirements"))
|
||||
setSectionPosition("requirements", m_requirementsPosition, position, true);
|
||||
else if (parser.probeIdentifier("objects", isIdentifier))
|
||||
else if (parser.testIdentifierAndSkip("objects"))
|
||||
setSectionPosition("objects", m_objectsPosition, position, true);
|
||||
else if (parser.probeIdentifier("init", isIdentifier))
|
||||
else if (parser.testIdentifierAndSkip("init"))
|
||||
setSectionPosition("init", m_initialStatePosition, position, true);
|
||||
else if (parser.probeIdentifier("goal", isIdentifier))
|
||||
else if (parser.testIdentifierAndSkip("goal"))
|
||||
setSectionPosition("goal", m_goalPosition, position, true);
|
||||
else if (parser.probeIdentifier("constraints", isIdentifier)
|
||||
|| parser.probeIdentifier("metric", isIdentifier)
|
||||
|| parser.probeIdentifier("length", isIdentifier))
|
||||
else if (parser.testIdentifierAndSkip("constraints")
|
||||
|| parser.testIdentifierAndSkip("metric")
|
||||
|| parser.testIdentifierAndSkip("length"))
|
||||
{
|
||||
parser.seek(sectionIdentifierPosition);
|
||||
|
||||
const auto sectionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto sectionIdentifier = parser.parseIdentifier();
|
||||
|
||||
m_context.logger.logWarning(parser, "section type “" + sectionIdentifier + "” currently unsupported");
|
||||
m_context.logger.logWarning(parser.coordinate(), "section type “" + sectionIdentifier + "” currently unsupported");
|
||||
|
||||
parser.seek(sectionIdentifierPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto sectionIdentifier = parser.parseIdentifier(isIdentifier);
|
||||
const auto sectionIdentifier = parser.parseIdentifier();
|
||||
|
||||
parser.seek(position);
|
||||
throw utils::ParserException(m_context.parser, "unknown problem section “" + sectionIdentifier + "”");
|
||||
throw utils::ParserException(parser.coordinate(), "unknown problem section “" + sectionIdentifier + "”");
|
||||
}
|
||||
|
||||
// Skip section for now and parse it later
|
||||
@@ -201,10 +200,10 @@ void Problem::parseDomainSection()
|
||||
|
||||
parser.skipWhiteSpace();
|
||||
|
||||
const auto domainName = parser.parseIdentifier(isIdentifier);
|
||||
const auto domainName = parser.parseIdentifier();
|
||||
|
||||
if (m_domain.name() != domainName)
|
||||
throw utils::ParserException(parser, "domains do not match (“" + m_domain.name() + "” and “" + domainName + "”)");
|
||||
throw utils::ParserException(parser.coordinate(), "domains do not match (“" + m_domain.name() + "” and “" + domainName + "”)");
|
||||
|
||||
parser.expect<std::string>(")");
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@
|
||||
#include <boost/assign.hpp>
|
||||
#include <boost/bimap.hpp>
|
||||
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/utils/IO.h>
|
||||
#include <plasp/utils/ParserException.h>
|
||||
|
||||
@@ -84,17 +83,19 @@ Requirement::Requirement(Requirement::Type type)
|
||||
|
||||
Requirement Requirement::parse(Context &context)
|
||||
{
|
||||
const auto requirementName = context.parser.parseIdentifier(isIdentifier);
|
||||
auto &parser = context.parser;
|
||||
|
||||
const auto requirementName = parser.parseIdentifier();
|
||||
|
||||
const auto match = requirementTypesToPDDL.right.find(requirementName);
|
||||
|
||||
if (match == requirementTypesToPDDL.right.end())
|
||||
throw utils::ParserException(context.parser, "unknown PDDL requirement “" + requirementName + "”");
|
||||
throw utils::ParserException(parser.coordinate(), "unknown PDDL requirement “" + requirementName + "”");
|
||||
|
||||
const auto requirementType = match->second;
|
||||
|
||||
if (requirementType == Requirement::Type::GoalUtilities)
|
||||
context.logger.logWarning(context.parser, "requirement “goal-utilities” is not part of the PDDL 3.1 specification");
|
||||
context.logger.logWarning(parser.coordinate(), "requirement “goal-utilities” is not part of the PDDL 3.1 specification");
|
||||
|
||||
return Requirement(match->second);
|
||||
}
|
||||
|
@@ -85,7 +85,10 @@ void TranslatorASP::translateTypes() const
|
||||
|
||||
if (types.empty())
|
||||
{
|
||||
m_outputStream << utils::Keyword("type") << "(object)." << std::endl;
|
||||
m_outputStream
|
||||
<< utils::Keyword("type") << "("
|
||||
<< utils::Keyword("type") << "(object))." << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -94,7 +97,10 @@ void TranslatorASP::translateTypes() const
|
||||
{
|
||||
const auto typeName = utils::escapeASP(type->name());
|
||||
|
||||
m_outputStream << utils::Keyword("type") << "(" << typeName << ")." << std::endl;
|
||||
m_outputStream
|
||||
<< utils::Keyword("type") << "("
|
||||
<< utils::Keyword("type") << "("
|
||||
<< typeName << "))." << std::endl;
|
||||
|
||||
const auto &parentTypes = type->parentTypes();
|
||||
|
||||
@@ -108,9 +114,9 @@ void TranslatorASP::translateTypes() const
|
||||
<< "(" << typeName << "), " << utils::Keyword("type")
|
||||
<< "(" << parentTypeName << "))." << std::endl
|
||||
|
||||
<< utils::Keyword("hasType") << "(" << utils::Variable("X") << ", "
|
||||
<< utils::Keyword("has") << "(" << utils::Variable("X") << ", "
|
||||
<< utils::Keyword("type") << "(" << parentTypeName << ")) :- "
|
||||
<< utils::Keyword("hasType") << "(" << utils::Variable("X") << ", "
|
||||
<< utils::Keyword("has") << "(" << utils::Variable("X") << ", "
|
||||
<< utils::Keyword("type") << "(" << typeName << "))." << std::endl;
|
||||
});
|
||||
});
|
||||
@@ -120,27 +126,59 @@ void TranslatorASP::translateTypes() const
|
||||
|
||||
void TranslatorASP::translatePredicates() const
|
||||
{
|
||||
m_outputStream << utils::Heading2("predicates");
|
||||
m_outputStream << utils::Heading2("variables");
|
||||
|
||||
const auto &predicates = m_description.domain().predicates();
|
||||
|
||||
const auto printPredicateName =
|
||||
[&](const auto &predicate)
|
||||
{
|
||||
m_outputStream
|
||||
<< utils::escapeASP(predicate->name());
|
||||
|
||||
this->translateVariablesHead(predicate->arguments());
|
||||
};
|
||||
|
||||
const auto printValueRule =
|
||||
[&](const auto &predicate, const auto &value)
|
||||
{
|
||||
m_outputStream
|
||||
<< utils::Keyword("contains") << "("
|
||||
<< utils::Keyword("variable") << "(";
|
||||
|
||||
printPredicateName(predicate);
|
||||
|
||||
m_outputStream
|
||||
<< "), " << utils::Keyword("value") << "(";
|
||||
|
||||
printPredicateName(predicate);
|
||||
|
||||
m_outputStream << ", " << utils::Keyword(value) << "))";
|
||||
|
||||
this->translateVariablesBody(predicate->arguments());
|
||||
|
||||
m_outputStream << "." << std::endl;
|
||||
};
|
||||
|
||||
std::for_each(predicates.cbegin(), predicates.cend(),
|
||||
[&](const auto &predicate)
|
||||
{
|
||||
m_outputStream << std::endl;
|
||||
m_outputStream
|
||||
<< std::endl
|
||||
<< utils::Keyword("variable") << "("
|
||||
<< utils::Keyword("variable") << "(";
|
||||
|
||||
m_outputStream << utils::Keyword("predicate") << "(" << utils::escapeASP(predicate->name());
|
||||
printPredicateName(predicate);
|
||||
|
||||
this->translateVariablesHead(predicate->arguments());
|
||||
|
||||
m_outputStream << ")";
|
||||
m_outputStream << "))";
|
||||
|
||||
this->translateVariablesBody(predicate->arguments());
|
||||
|
||||
m_outputStream << ".";
|
||||
});
|
||||
m_outputStream << "." << std::endl;
|
||||
|
||||
m_outputStream << std::endl;
|
||||
printValueRule(predicate, "true");
|
||||
printValueRule(predicate, "false");
|
||||
});
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -164,28 +202,35 @@ void TranslatorASP::translateActions() const
|
||||
std::for_each(actions.cbegin(), actions.cend(),
|
||||
[&](const auto &action)
|
||||
{
|
||||
// TODO: rename
|
||||
const auto translateLiteral =
|
||||
[&](const auto &ruleHead, const auto &literal)
|
||||
[&](const auto &ruleHead, const auto &literal, bool enumerateEffects = false)
|
||||
{
|
||||
m_outputStream << std::endl << utils::Keyword(ruleHead) << "(";
|
||||
|
||||
printActionName(*action);
|
||||
|
||||
// TODO: implement conditional effects
|
||||
if (enumerateEffects)
|
||||
m_outputStream << ", " << utils::Keyword("effect") << "(unconditional)";
|
||||
|
||||
m_outputStream << ", ";
|
||||
|
||||
this->translateLiteral(literal);
|
||||
|
||||
m_outputStream << ") :- ";
|
||||
m_outputStream << ") :- " << utils::Keyword("action") << "(";
|
||||
|
||||
printActionName(*action);
|
||||
|
||||
m_outputStream << ".";
|
||||
m_outputStream << ").";
|
||||
};
|
||||
|
||||
m_outputStream << std::endl;
|
||||
|
||||
// Name
|
||||
m_outputStream << utils::Keyword("action") << "(";
|
||||
printActionName(*action);
|
||||
m_outputStream << ")";
|
||||
|
||||
this->translateVariablesBody(action->parameters());
|
||||
|
||||
@@ -225,7 +270,7 @@ void TranslatorASP::translateActions() const
|
||||
if (effect.expressionType() == Expression::Type::Predicate
|
||||
|| effect.expressionType() == Expression::Type::Not)
|
||||
{
|
||||
translateLiteral("postcondition", effect);
|
||||
translateLiteral("postcondition", effect, true);
|
||||
}
|
||||
// Assuming a conjunction
|
||||
else
|
||||
@@ -238,7 +283,7 @@ void TranslatorASP::translateActions() const
|
||||
std::for_each(andExpression.arguments().cbegin(), andExpression.arguments().cend(),
|
||||
[&](const auto *argument)
|
||||
{
|
||||
translateLiteral("postcondition", *argument);
|
||||
translateLiteral("postcondition", *argument, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -258,20 +303,23 @@ void TranslatorASP::translateConstants(const std::string &heading, const express
|
||||
{
|
||||
const auto constantName = utils::escapeASP(constant->name());
|
||||
|
||||
m_outputStream << std::endl << utils::Keyword("constant")
|
||||
<< "(" << constantName << ")." << std::endl;
|
||||
m_outputStream << std::endl
|
||||
<< utils::Keyword("constant") << "("
|
||||
<< utils::Keyword("constant") << "("
|
||||
<< constantName
|
||||
<< "))." << std::endl;
|
||||
|
||||
const auto *type = constant->type();
|
||||
|
||||
if (type != nullptr)
|
||||
{
|
||||
m_outputStream << utils::Keyword("hasType") << "("
|
||||
m_outputStream << utils::Keyword("has") << "("
|
||||
<< utils::Keyword("constant") << "(" << constantName << "), "
|
||||
<< utils::Keyword("type") << "(" << utils::escapeASP(type->name()) << "))." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_outputStream << utils::Keyword("hasType") << "("
|
||||
m_outputStream << utils::Keyword("has") << "("
|
||||
<< utils::Keyword("constant") << "(" << constantName << "), "
|
||||
<< utils::Keyword("type") << "(object))." << std::endl;
|
||||
}
|
||||
@@ -323,13 +371,13 @@ void TranslatorASP::translateVariablesBody(const expressions::Variables &variabl
|
||||
|
||||
const auto &type = *dynamic_cast<const expressions::PrimitiveType *>(variable.type());
|
||||
|
||||
m_outputStream << utils::Keyword("hasType") << "("
|
||||
m_outputStream << utils::Keyword("has") << "("
|
||||
<< utils::Variable(utils::escapeASPVariable(variable.name())) << ", "
|
||||
<< utils::Keyword("type") << "(" << utils::escapeASP(type.name()) << "))";
|
||||
}
|
||||
else
|
||||
{
|
||||
m_outputStream << utils::Keyword("hasType") << "("
|
||||
m_outputStream << utils::Keyword("has") << "("
|
||||
<< utils::Variable(utils::escapeASPVariable(variable.name())) << ", "
|
||||
<< utils::Keyword("type") << "(object))";
|
||||
}
|
||||
@@ -343,8 +391,13 @@ void TranslatorASP::translateLiteral(const Expression &literal) const
|
||||
// Translate single predicate
|
||||
if (literal.expressionType() == Expression::Type::Predicate)
|
||||
{
|
||||
this->translatePredicate(dynamic_cast<const expressions::Predicate &>(literal));
|
||||
m_outputStream << ", " << utils::Keyword("true");
|
||||
const auto &predicate = dynamic_cast<const expressions::Predicate &>(literal);
|
||||
|
||||
m_outputStream << utils::Keyword("variable") << "(";
|
||||
this->translatePredicate(predicate);
|
||||
m_outputStream << "), " << utils::Keyword("value") << "(";
|
||||
this->translatePredicate(predicate);
|
||||
m_outputStream << ", " << utils::Keyword("true") << ")";
|
||||
}
|
||||
// Assuming that "not" expression may only contain a predicate
|
||||
else if (literal.expressionType() == Expression::Type::Not)
|
||||
@@ -352,8 +405,11 @@ void TranslatorASP::translateLiteral(const Expression &literal) const
|
||||
const auto ¬Expression = dynamic_cast<const expressions::Not &>(literal);
|
||||
const auto &predicate = dynamic_cast<const expressions::Predicate &>(*notExpression.argument());
|
||||
|
||||
m_outputStream << utils::Keyword("variable") << "(";
|
||||
this->translatePredicate(predicate);
|
||||
m_outputStream << ", " << utils::Keyword("false");
|
||||
m_outputStream << "), " << utils::Keyword("value") << "(";
|
||||
this->translatePredicate(predicate);
|
||||
m_outputStream << ", " << utils::Keyword("false") << ")";
|
||||
}
|
||||
else
|
||||
throw utils::TranslatorException("only primitive predicates and their negations supported as literals currently");
|
||||
@@ -363,13 +419,12 @@ void TranslatorASP::translateLiteral(const Expression &literal) const
|
||||
|
||||
void TranslatorASP::translatePredicate(const expressions::Predicate &predicate) const
|
||||
{
|
||||
m_outputStream << utils::Keyword("predicate") << "(" << utils::escapeASP(predicate.name());
|
||||
m_outputStream << utils::escapeASP(predicate.name());
|
||||
|
||||
const auto &arguments = predicate.arguments();
|
||||
|
||||
if (arguments.empty())
|
||||
{
|
||||
m_outputStream << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -396,7 +451,7 @@ void TranslatorASP::translatePredicate(const expressions::Predicate &predicate)
|
||||
throw utils::TranslatorException("only variables and constants supported in predicates currently");
|
||||
}
|
||||
|
||||
m_outputStream << "))";
|
||||
m_outputStream << ")";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -442,7 +497,15 @@ void TranslatorASP::translateInitialState() const
|
||||
|
||||
// Translate single predicate
|
||||
if (fact->expressionType() == Expression::Type::Predicate)
|
||||
this->translatePredicate(dynamic_cast<const expressions::Predicate &>(*fact));
|
||||
{
|
||||
const auto &predicate = dynamic_cast<const expressions::Predicate &>(*fact);
|
||||
|
||||
m_outputStream << utils::Keyword("variable") << "(";
|
||||
this->translatePredicate(predicate);
|
||||
m_outputStream << "), " << utils::Keyword("value") << "(";
|
||||
this->translatePredicate(predicate);
|
||||
m_outputStream << ", " << utils::Keyword("true") << ")";
|
||||
}
|
||||
// Assuming that "not" expression may only contain a predicate
|
||||
else if (fact->expressionType() == Expression::Type::Not)
|
||||
{
|
||||
|
@@ -37,7 +37,7 @@ ConstantPointer Constant::parseDeclaration(Context &context)
|
||||
|
||||
auto constant = std::make_unique<Constant>(Constant());
|
||||
|
||||
constant->m_name = context.parser.parseIdentifier(isIdentifier);
|
||||
constant->m_name = context.parser.parseIdentifier();
|
||||
|
||||
BOOST_ASSERT(constant->m_name != "-");
|
||||
|
||||
@@ -71,7 +71,7 @@ void Constant::parseTypedDeclaration(Context &context, Domain &domain, Constants
|
||||
context.parser.skipWhiteSpace();
|
||||
|
||||
// Check for typing information
|
||||
if (!context.parser.probe('-'))
|
||||
if (!context.parser.testAndSkip<char>('-'))
|
||||
return;
|
||||
|
||||
// If existing, parse and store parent type
|
||||
@@ -113,7 +113,7 @@ void Constant::parseTypedDeclarations(Context &context, Domain &domain)
|
||||
domain.checkRequirement(Requirement::Type::Typing);
|
||||
// If no types are given, check that typing is not a requirement
|
||||
else if (domain.hasRequirement(Requirement::Type::Typing))
|
||||
throw utils::ParserException(parser, "constant has undeclared type");
|
||||
throw utils::ParserException(parser.coordinate(), "constant has undeclared type");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -140,32 +140,36 @@ void Constant::parseTypedDeclarations(Context &context, Problem &problem)
|
||||
problem.checkRequirement(Requirement::Type::Typing);
|
||||
// If no types are given, check that typing is not a requirement
|
||||
else if (problem.hasRequirement(Requirement::Type::Typing))
|
||||
throw utils::ParserException(context.parser, "constant has undeclared type");
|
||||
throw utils::ParserException(parser.coordinate(), "constant has undeclared type");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Constant *Constant::parseAndFind(Context &context, const Domain &domain)
|
||||
{
|
||||
context.parser.skipWhiteSpace();
|
||||
auto &parser = context.parser;
|
||||
|
||||
const auto constantName = context.parser.parseIdentifier(isIdentifier);
|
||||
parser.skipWhiteSpace();
|
||||
|
||||
const auto constantName = parser.parseIdentifier();
|
||||
|
||||
auto *constant = parseAndFind(constantName, domain.constants());
|
||||
|
||||
if (constant != nullptr)
|
||||
return constant;
|
||||
|
||||
throw utils::ParserException(context.parser, "constant “" + constantName + "” used but never declared");
|
||||
throw utils::ParserException(parser.coordinate(), "constant “" + constantName + "” used but never declared");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Constant *Constant::parseAndFind(Context &context, const Problem &problem)
|
||||
{
|
||||
context.parser.skipWhiteSpace();
|
||||
auto &parser = context.parser;
|
||||
|
||||
const auto constantName = context.parser.parseIdentifier(isIdentifier);
|
||||
parser.skipWhiteSpace();
|
||||
|
||||
const auto constantName = parser.parseIdentifier();
|
||||
|
||||
auto *constant = parseAndFind(constantName, problem.domain().constants());
|
||||
|
||||
@@ -177,7 +181,7 @@ Constant *Constant::parseAndFind(Context &context, const Problem &problem)
|
||||
if (constant)
|
||||
return constant;
|
||||
|
||||
throw utils::ParserException(context.parser, "constant “" + constantName + "” used but never declared");
|
||||
throw utils::ParserException(parser.coordinate(), "constant “" + constantName + "” used but never declared");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@@ -13,6 +13,7 @@ namespace expressions
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// TODO: make static character string literal
|
||||
const std::string Imply::Identifier = "imply";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@@ -3,7 +3,6 @@
|
||||
#include <plasp/pddl/Context.h>
|
||||
#include <plasp/pddl/Domain.h>
|
||||
#include <plasp/pddl/ExpressionContext.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/pddl/Problem.h>
|
||||
#include <plasp/pddl/expressions/Constant.h>
|
||||
#include <plasp/pddl/expressions/Variable.h>
|
||||
@@ -34,13 +33,13 @@ PredicatePointer Predicate::parse(Context &context, ExpressionContext &expressio
|
||||
|
||||
const auto position = parser.position();
|
||||
|
||||
if (!parser.probe<std::string>("("))
|
||||
if (!parser.testAndSkip<std::string>("("))
|
||||
{
|
||||
parser.seek(position);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto predicateName = parser.parseIdentifier(isIdentifier);
|
||||
const auto predicateName = parser.parseIdentifier();
|
||||
const auto &predicates = expressionContext.domain.predicates();
|
||||
|
||||
const auto matchingPredicate = std::find_if(predicates.cbegin(), predicates.cend(),
|
||||
@@ -97,13 +96,13 @@ PredicatePointer Predicate::parse(Context &context, const Problem &problem)
|
||||
|
||||
const auto position = parser.position();
|
||||
|
||||
if (!parser.probe<std::string>("("))
|
||||
if (!parser.testAndSkip<std::string>("("))
|
||||
{
|
||||
parser.seek(position);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto predicateName = parser.parseIdentifier(isIdentifier);
|
||||
const auto predicateName = parser.parseIdentifier();
|
||||
const auto &predicates = problem.domain().predicates();
|
||||
|
||||
const auto matchingPredicate = std::find_if(predicates.cbegin(), predicates.cend(),
|
||||
@@ -122,12 +121,12 @@ PredicatePointer Predicate::parse(Context &context, const Problem &problem)
|
||||
|
||||
predicate->m_name = predicateName;
|
||||
|
||||
context.parser.skipWhiteSpace();
|
||||
parser.skipWhiteSpace();
|
||||
|
||||
while (context.parser.currentCharacter() != ')')
|
||||
while (parser.currentCharacter() != ')')
|
||||
{
|
||||
if (context.parser.currentCharacter() == '?')
|
||||
throw utils::ParserException(context.parser, "variables not allowed in this context");
|
||||
if (parser.currentCharacter() == '?')
|
||||
throw utils::ParserException(parser.coordinate(), "variables not allowed in this context");
|
||||
|
||||
// Parse objects and constants
|
||||
const auto *constant = Constant::parseAndFind(context, problem);
|
||||
|
@@ -3,7 +3,6 @@
|
||||
#include <plasp/pddl/Context.h>
|
||||
#include <plasp/pddl/Domain.h>
|
||||
#include <plasp/pddl/ExpressionContext.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/pddl/expressions/Constant.h>
|
||||
#include <plasp/pddl/expressions/Variable.h>
|
||||
|
||||
@@ -33,7 +32,7 @@ void PredicateDeclaration::parse(Context &context, Domain &domain)
|
||||
|
||||
auto predicate = std::make_unique<PredicateDeclaration>(PredicateDeclaration());
|
||||
|
||||
predicate->m_name = context.parser.parseIdentifier(isIdentifier);
|
||||
predicate->m_name = context.parser.parseIdentifier();
|
||||
|
||||
// Flag predicate as correctly declared in the types section
|
||||
predicate->setDeclared();
|
||||
|
@@ -43,7 +43,7 @@ void PrimitiveType::parseDeclaration(Context &context, Domain &domain)
|
||||
|
||||
context.parser.skipWhiteSpace();
|
||||
|
||||
const auto typeName = context.parser.parseIdentifier(isIdentifier);
|
||||
const auto typeName = context.parser.parseIdentifier();
|
||||
|
||||
const auto match = std::find_if(types.cbegin(), types.cend(),
|
||||
[&](const auto &primitiveType)
|
||||
@@ -76,7 +76,7 @@ void PrimitiveType::parseTypedDeclaration(Context &context, Domain &domain)
|
||||
context.parser.skipWhiteSpace();
|
||||
|
||||
// Check for type inheritance
|
||||
if (!context.parser.probe('-'))
|
||||
if (!context.parser.testAndSkip<char>('-'))
|
||||
return;
|
||||
|
||||
domain.checkRequirement(Requirement::Type::Typing);
|
||||
@@ -102,14 +102,16 @@ void PrimitiveType::parseTypedDeclaration(Context &context, Domain &domain)
|
||||
|
||||
PrimitiveType *PrimitiveType::parseAndFind(Context &context, Domain &domain)
|
||||
{
|
||||
auto &parser = context.parser;
|
||||
|
||||
auto &types = domain.types();
|
||||
|
||||
context.parser.skipWhiteSpace();
|
||||
parser.skipWhiteSpace();
|
||||
|
||||
const auto typeName = context.parser.parseIdentifier(isIdentifier);
|
||||
const auto typeName = parser.parseIdentifier();
|
||||
|
||||
if (typeName.empty())
|
||||
throw utils::ParserException(context.parser, "no type supplied");
|
||||
throw utils::ParserException(parser.coordinate(), "no type supplied");
|
||||
|
||||
const auto match = std::find_if(types.cbegin(), types.cend(),
|
||||
[&](const auto &primitiveType)
|
||||
@@ -122,11 +124,11 @@ PrimitiveType *PrimitiveType::parseAndFind(Context &context, Domain &domain)
|
||||
// Only "object" is allowed as an implicit type
|
||||
if (typeName == "object" || typeName == "objects")
|
||||
{
|
||||
context.logger.logWarning(context.parser, "primitive type “" + typeName + "” should be declared");
|
||||
context.logger.logWarning(parser.coordinate(), "primitive type “" + typeName + "” should be declared");
|
||||
types.emplace_back(std::make_unique<expressions::PrimitiveType>(typeName));
|
||||
}
|
||||
else
|
||||
throw utils::ParserException(context.parser, "type “" + typeName + "” used but never declared");
|
||||
throw utils::ParserException(parser.coordinate(), "type “" + typeName + "” used but never declared");
|
||||
|
||||
return types.back().get();
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
#include <plasp/pddl/expressions/Unsupported.h>
|
||||
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/pddl/IO.h>
|
||||
|
||||
namespace plasp
|
||||
@@ -24,9 +23,9 @@ UnsupportedPointer Unsupported::parse(Context &context)
|
||||
|
||||
parser.expect<std::string>("(");
|
||||
|
||||
expression->m_type = parser.parseIdentifier(isIdentifier);
|
||||
expression->m_type = parser.parseIdentifier();
|
||||
|
||||
context.logger.logWarning(context.parser, "expression type “" + expression->m_type + "” currently unsupported in this context");
|
||||
context.logger.logWarning(parser.coordinate(), "expression type “" + expression->m_type + "” currently unsupported in this context");
|
||||
|
||||
skipSection(parser);
|
||||
|
||||
|
@@ -7,7 +7,6 @@
|
||||
#include <plasp/pddl/Context.h>
|
||||
#include <plasp/pddl/Domain.h>
|
||||
#include <plasp/pddl/ExpressionContext.h>
|
||||
#include <plasp/pddl/Identifier.h>
|
||||
#include <plasp/pddl/expressions/Either.h>
|
||||
#include <plasp/pddl/expressions/PrimitiveType.h>
|
||||
#include <plasp/pddl/expressions/Type.h>
|
||||
@@ -36,13 +35,15 @@ Variable::Variable()
|
||||
|
||||
void Variable::parseDeclaration(Context &context, Variables ¶meters)
|
||||
{
|
||||
context.parser.skipWhiteSpace();
|
||||
auto &parser = context.parser;
|
||||
|
||||
context.parser.expect<std::string>("?");
|
||||
parser.skipWhiteSpace();
|
||||
|
||||
parser.expect<std::string>("?");
|
||||
|
||||
auto variable = std::make_unique<Variable>(Variable());
|
||||
|
||||
variable->m_name = context.parser.parseIdentifier(isIdentifier);
|
||||
variable->m_name = parser.parseIdentifier();
|
||||
|
||||
// Check if variable of that name already exists in the current scope
|
||||
const auto match = std::find_if(parameters.cbegin(), parameters.cend(),
|
||||
@@ -52,7 +53,7 @@ void Variable::parseDeclaration(Context &context, Variables ¶meters)
|
||||
});
|
||||
|
||||
if (match != parameters.cend())
|
||||
throw utils::ParserException(context.parser, "variable “" + variable->m_name + "” already declared in this scope");
|
||||
throw utils::ParserException(parser.coordinate(), "variable “" + variable->m_name + "” already declared in this scope");
|
||||
|
||||
// Flag variable for potentially upcoming type declaration
|
||||
variable->setDirty();
|
||||
@@ -75,7 +76,7 @@ void Variable::parseTypedDeclaration(Context &context, ExpressionContext &expres
|
||||
parser.skipWhiteSpace();
|
||||
|
||||
// Check if the variable has a type declaration
|
||||
if (!parser.probe('-'))
|
||||
if (!parser.testAndSkip<char>('-'))
|
||||
return;
|
||||
|
||||
const auto setType =
|
||||
@@ -132,18 +133,20 @@ void Variable::parseTypedDeclarations(Context &context, ExpressionContext &expre
|
||||
expressionContext.checkRequirement(Requirement::Type::Typing);
|
||||
// If no types are given, check that typing is not a requirement
|
||||
else if (expressionContext.hasRequirement(Requirement::Type::Typing))
|
||||
throw utils::ParserException(parser, "variable has undeclared type");
|
||||
throw utils::ParserException(parser.coordinate(), "variable has undeclared type");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const Variable *Variable::parseAndFind(Context &context, const ExpressionContext &expressionContext)
|
||||
{
|
||||
context.parser.skipWhiteSpace();
|
||||
auto &parser = context.parser;
|
||||
|
||||
context.parser.expect<std::string>("?");
|
||||
parser.skipWhiteSpace();
|
||||
|
||||
const auto variableName = context.parser.parseIdentifier(isIdentifier);
|
||||
parser.expect<std::string>("?");
|
||||
|
||||
const auto variableName = parser.parseIdentifier();
|
||||
|
||||
const auto &variables = expressionContext.parameters;
|
||||
|
||||
@@ -154,7 +157,7 @@ const Variable *Variable::parseAndFind(Context &context, const ExpressionContext
|
||||
});
|
||||
|
||||
if (match == variables.cend())
|
||||
throw utils::ParserException(context.parser, "parameter “" + variableName + "” used but never declared");
|
||||
throw utils::ParserException(parser.coordinate(), "parameter “" + variableName + "” used but never declared");
|
||||
|
||||
return match->get();
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ AssignedVariable::AssignedVariable(const Variable &variable, const Value &value)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AssignedVariable AssignedVariable::fromSAS(utils::Parser &parser, const Variables &variables)
|
||||
AssignedVariable AssignedVariable::fromSAS(utils::Parser<> &parser, const Variables &variables)
|
||||
{
|
||||
AssignedVariable assignedVariable;
|
||||
|
||||
@@ -43,7 +43,7 @@ AssignedVariable AssignedVariable::fromSAS(utils::Parser &parser, const Variable
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AssignedVariable AssignedVariable::fromSAS(utils::Parser &parser, const Variable &variable)
|
||||
AssignedVariable AssignedVariable::fromSAS(utils::Parser<> &parser, const Variable &variable)
|
||||
{
|
||||
AssignedVariable assignedVariable;
|
||||
|
||||
|
@@ -23,7 +23,7 @@ AxiomRule::AxiomRule(AxiomRule::Conditions conditions, AxiomRule::Condition post
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AxiomRule AxiomRule::fromSAS(utils::Parser &parser, const Variables &variables)
|
||||
AxiomRule AxiomRule::fromSAS(utils::Parser<> &parser, const Variables &variables)
|
||||
{
|
||||
parser.expect<std::string>("begin_rule");
|
||||
|
||||
|
@@ -28,10 +28,8 @@ Description::Description()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Description Description::fromParser(utils::Parser &&parser)
|
||||
Description Description::fromParser(utils::Parser<> &&parser)
|
||||
{
|
||||
parser.setCaseSensitive(true);
|
||||
|
||||
Description description;
|
||||
description.parseContent(parser);
|
||||
|
||||
@@ -42,8 +40,8 @@ Description Description::fromParser(utils::Parser &&parser)
|
||||
|
||||
Description Description::fromStream(std::istream &istream)
|
||||
{
|
||||
utils::Parser parser;
|
||||
parser.readStream("std::cin", istream);
|
||||
utils::Parser<> parser;
|
||||
parser.read("std::cin", istream);
|
||||
|
||||
Description description;
|
||||
description.parseContent(parser);
|
||||
@@ -58,8 +56,8 @@ Description Description::fromFile(const boost::filesystem::path &path)
|
||||
if (!boost::filesystem::is_regular_file(path))
|
||||
throw std::runtime_error("File does not exist: “" + path.string() + "”");
|
||||
|
||||
utils::Parser parser;
|
||||
parser.readFile(path);
|
||||
utils::Parser<> parser;
|
||||
parser.read(path);
|
||||
|
||||
Description description;
|
||||
description.parseContent(parser);
|
||||
@@ -155,7 +153,14 @@ bool Description::usesConditionalEffects() const
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Description::parseContent(utils::Parser &parser)
|
||||
bool Description::hasRequirements() const
|
||||
{
|
||||
return usesActionCosts() || usesAxiomRules() || usesConditionalEffects();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Description::parseContent(utils::Parser<> &parser)
|
||||
{
|
||||
parseVersionSection(parser);
|
||||
parseMetricSection(parser);
|
||||
@@ -168,27 +173,27 @@ void Description::parseContent(utils::Parser &parser)
|
||||
|
||||
parser.skipWhiteSpace();
|
||||
|
||||
if (!parser.atEndOfStream())
|
||||
throw utils::ParserException(parser, "expected end of SAS description (perhaps, input contains two SAS descriptions?)");
|
||||
if (!parser.atEnd())
|
||||
throw utils::ParserException(parser.coordinate(), "expected end of SAS description (perhaps, input contains two SAS descriptions?)");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Description::parseVersionSection(utils::Parser &parser) const
|
||||
void Description::parseVersionSection(utils::Parser<> &parser) const
|
||||
{
|
||||
parser.expect<std::string>("begin_version");
|
||||
|
||||
const auto formatVersion = parser.parse<size_t>();
|
||||
|
||||
if (formatVersion != 3)
|
||||
throw utils::ParserException(parser, "unsupported SAS format version (" + std::to_string(formatVersion) + ")");
|
||||
throw utils::ParserException(parser.coordinate(), "unsupported SAS format version (" + std::to_string(formatVersion) + ")");
|
||||
|
||||
parser.expect<std::string>("end_version");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Description::parseMetricSection(utils::Parser &parser)
|
||||
void Description::parseMetricSection(utils::Parser<> &parser)
|
||||
{
|
||||
parser.expect<std::string>("begin_metric");
|
||||
|
||||
@@ -199,7 +204,7 @@ void Description::parseMetricSection(utils::Parser &parser)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Description::parseVariablesSection(utils::Parser &parser)
|
||||
void Description::parseVariablesSection(utils::Parser<> &parser)
|
||||
{
|
||||
const auto numberOfVariables = parser.parse<size_t>();
|
||||
m_variables.reserve(numberOfVariables);
|
||||
@@ -210,7 +215,7 @@ void Description::parseVariablesSection(utils::Parser &parser)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Description::parseMutexSection(utils::Parser &parser)
|
||||
void Description::parseMutexSection(utils::Parser<> &parser)
|
||||
{
|
||||
const auto numberOfMutexGroups = parser.parse<size_t>();
|
||||
m_mutexGroups.reserve(numberOfMutexGroups);
|
||||
@@ -221,21 +226,21 @@ void Description::parseMutexSection(utils::Parser &parser)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Description::parseInitialStateSection(utils::Parser &parser)
|
||||
void Description::parseInitialStateSection(utils::Parser<> &parser)
|
||||
{
|
||||
m_initialState = std::make_unique<InitialState>(InitialState::fromSAS(parser, m_variables));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Description::parseGoalSection(utils::Parser &parser)
|
||||
void Description::parseGoalSection(utils::Parser<> &parser)
|
||||
{
|
||||
m_goal = std::make_unique<Goal>(Goal::fromSAS(parser, m_variables));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Description::parseOperatorSection(utils::Parser &parser)
|
||||
void Description::parseOperatorSection(utils::Parser<> &parser)
|
||||
{
|
||||
const auto numberOfOperators = parser.parse<size_t>();
|
||||
m_operators.reserve(numberOfOperators);
|
||||
@@ -246,7 +251,7 @@ void Description::parseOperatorSection(utils::Parser &parser)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Description::parseAxiomSection(utils::Parser &parser)
|
||||
void Description::parseAxiomSection(utils::Parser<> &parser)
|
||||
{
|
||||
const auto numberOfAxiomRules = parser.parse<size_t>();
|
||||
m_axiomRules.reserve(numberOfAxiomRules);
|
||||
|
@@ -23,7 +23,7 @@ Effect::Effect(Conditions conditions, Condition postcondition)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Effect Effect::fromSAS(utils::Parser &parser, const Variables &variables, Conditions &preconditions)
|
||||
Effect Effect::fromSAS(utils::Parser<> &parser, const Variables &variables, Conditions &preconditions)
|
||||
{
|
||||
Effect::Conditions conditions;
|
||||
|
||||
|
@@ -13,7 +13,7 @@ namespace sas
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Goal Goal::fromSAS(utils::Parser &parser, const Variables &variables)
|
||||
Goal Goal::fromSAS(utils::Parser<> &parser, const Variables &variables)
|
||||
{
|
||||
Goal goal;
|
||||
|
||||
|
@@ -11,7 +11,7 @@ namespace sas
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
InitialState InitialState::fromSAS(utils::Parser &parser, const Variables &variables)
|
||||
InitialState InitialState::fromSAS(utils::Parser<> &parser, const Variables &variables)
|
||||
{
|
||||
InitialState initialState;
|
||||
|
||||
|
@@ -15,7 +15,7 @@ namespace sas
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MutexGroup MutexGroup::fromSAS(utils::Parser &parser, const Variables &variables)
|
||||
MutexGroup MutexGroup::fromSAS(utils::Parser<> &parser, const Variables &variables)
|
||||
{
|
||||
MutexGroup mutexGroup;
|
||||
|
||||
@@ -29,7 +29,7 @@ MutexGroup MutexGroup::fromSAS(utils::Parser &parser, const Variables &variables
|
||||
mutexGroup.m_facts.emplace_back(Fact::fromSAS(parser, variables));
|
||||
|
||||
if (mutexGroup.m_facts[j].value() == Value::None)
|
||||
throw utils::ParserException(parser, "mutex groups must not contain <none of those> values");
|
||||
throw utils::ParserException(parser.coordinate(), "mutex groups must not contain <none of those> values");
|
||||
}
|
||||
|
||||
parser.expect<std::string>("end_mutex_group");
|
||||
|
@@ -17,7 +17,7 @@ namespace sas
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Operator Operator::fromSAS(utils::Parser &parser, const Variables &variables)
|
||||
Operator Operator::fromSAS(utils::Parser<> &parser, const Variables &variables)
|
||||
{
|
||||
Operator operator_;
|
||||
|
||||
|
@@ -18,7 +18,7 @@ namespace sas
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Predicate Predicate::fromSAS(utils::Parser &parser)
|
||||
Predicate Predicate::fromSAS(utils::Parser<> &parser)
|
||||
{
|
||||
Predicate predicate;
|
||||
|
||||
@@ -31,11 +31,12 @@ Predicate Predicate::fromSAS(utils::Parser &parser)
|
||||
while (true)
|
||||
{
|
||||
// Parse arguments until reaching newline
|
||||
parser.skipWhiteSpace(
|
||||
// TODO: reimplement
|
||||
/*parser.skipWhiteSpace(
|
||||
[&](const auto character)
|
||||
{
|
||||
return character != '\n' && std::isspace(character);
|
||||
});
|
||||
});*/
|
||||
|
||||
if (parser.currentCharacter() == '\n')
|
||||
break;
|
||||
@@ -46,7 +47,7 @@ Predicate Predicate::fromSAS(utils::Parser &parser)
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw utils::ParserException(parser, "could not parse operator predicate");
|
||||
throw utils::ParserException(parser.coordinate(), "could not parse operator predicate");
|
||||
}
|
||||
|
||||
return predicate;
|
||||
|
@@ -22,16 +22,32 @@ TranslatorASP::TranslatorASP(const Description &description, utils::LogStream &o
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TranslatorASP::translate() const
|
||||
{
|
||||
// TODO: remove double computation of requirements
|
||||
if (m_description.hasRequirements())
|
||||
{
|
||||
translateRequirements();
|
||||
translateInitialState();
|
||||
translateGoal();
|
||||
m_outputStream << std::endl;
|
||||
}
|
||||
|
||||
translateVariables();
|
||||
m_outputStream << std::endl;
|
||||
translateActions();
|
||||
m_outputStream << std::endl;
|
||||
translateMutexes();
|
||||
|
||||
if (m_description.usesAxiomRules())
|
||||
{
|
||||
m_outputStream << std::endl;
|
||||
translateAxiomRules();
|
||||
}
|
||||
|
||||
m_outputStream << std::endl;
|
||||
translateInitialState();
|
||||
m_outputStream << std::endl;
|
||||
translateGoal();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TranslatorASP::translateRequirements() const
|
||||
@@ -39,15 +55,13 @@ void TranslatorASP::translateRequirements() const
|
||||
m_outputStream << utils::Heading2("feature requirements") << std::endl;
|
||||
|
||||
if (m_description.usesActionCosts())
|
||||
m_outputStream << utils::Keyword("requiresFeature") << "(actionCosts)." << std::endl;
|
||||
m_outputStream << utils::Keyword("requires") << "(" << utils::Keyword("feature") << "(actionCosts))." << std::endl;
|
||||
|
||||
if (m_description.usesAxiomRules())
|
||||
m_outputStream << utils::Keyword("requiresFeature") << "(axiomRules)." << std::endl;
|
||||
m_outputStream << utils::Keyword("requires") << "(" << utils::Keyword("feature") << "(axiomRules))." << std::endl;
|
||||
|
||||
if (m_description.usesConditionalEffects())
|
||||
m_outputStream << utils::Keyword("requiresFeature") << "(conditionalEffects)." << std::endl;
|
||||
|
||||
m_outputStream << std::endl;
|
||||
m_outputStream << utils::Keyword("requires") << "(" << utils::Keyword("feature") << "(conditionalEffects))." << std::endl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -67,8 +81,6 @@ void TranslatorASP::translateInitialState() const
|
||||
fact.value().printAsASPPredicate(m_outputStream);
|
||||
m_outputStream << ")." << std::endl;
|
||||
});
|
||||
|
||||
m_outputStream << std::endl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -88,8 +100,6 @@ void TranslatorASP::translateGoal() const
|
||||
fact.value().printAsASPPredicate(m_outputStream);
|
||||
m_outputStream << ")." << std::endl;
|
||||
});
|
||||
|
||||
m_outputStream << std::endl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -107,9 +117,9 @@ void TranslatorASP::translateVariables() const
|
||||
|
||||
BOOST_ASSERT(!values.empty());
|
||||
|
||||
m_outputStream << std::endl;
|
||||
m_outputStream << std::endl << utils::Keyword("variable") << "(";
|
||||
variable.printNameAsASPPredicate(m_outputStream);
|
||||
m_outputStream << "." << std::endl;
|
||||
m_outputStream << ")." << std::endl;
|
||||
|
||||
std::for_each(values.cbegin(), values.cend(),
|
||||
[&](const auto &value)
|
||||
@@ -121,8 +131,6 @@ void TranslatorASP::translateVariables() const
|
||||
m_outputStream << ")." << std::endl;
|
||||
});
|
||||
});
|
||||
|
||||
m_outputStream << std::endl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -133,12 +141,14 @@ void TranslatorASP::translateActions() const
|
||||
|
||||
const auto &operators = m_description.operators();
|
||||
|
||||
size_t currentEffectID = 0;
|
||||
|
||||
std::for_each(operators.cbegin(), operators.cend(),
|
||||
[&](const auto &operator_)
|
||||
{
|
||||
m_outputStream << std::endl;
|
||||
m_outputStream << std::endl << utils::Keyword("action") << "(";
|
||||
operator_.printPredicateAsASP(m_outputStream);
|
||||
m_outputStream << "." << std::endl;
|
||||
m_outputStream << ")." << std::endl;
|
||||
|
||||
const auto &preconditions = operator_.preconditions();
|
||||
|
||||
@@ -156,8 +166,6 @@ void TranslatorASP::translateActions() const
|
||||
|
||||
const auto &effects = operator_.effects();
|
||||
|
||||
size_t currentEffectID = 0;
|
||||
|
||||
std::for_each(effects.cbegin(), effects.cend(),
|
||||
[&](const auto &effect)
|
||||
{
|
||||
@@ -166,7 +174,8 @@ void TranslatorASP::translateActions() const
|
||||
std::for_each(conditions.cbegin(), conditions.cend(),
|
||||
[&](const auto &condition)
|
||||
{
|
||||
m_outputStream << utils::Keyword("effectCondition") << "(";
|
||||
// Conditions of conditional effects
|
||||
m_outputStream << utils::Keyword("precondition") << "(";
|
||||
operator_.printPredicateAsASP(m_outputStream);
|
||||
m_outputStream << ", " << utils::Keyword("effect") << "(" << utils::Number(std::to_string(currentEffectID)) << "), ";
|
||||
condition.variable().printNameAsASPPredicate(m_outputStream);
|
||||
@@ -177,21 +186,25 @@ void TranslatorASP::translateActions() const
|
||||
|
||||
m_outputStream << utils::Keyword("postcondition") << "(";
|
||||
operator_.printPredicateAsASP(m_outputStream);
|
||||
|
||||
if (conditions.empty())
|
||||
m_outputStream << ", " << utils::Keyword("effect") << "(unconditional), ";
|
||||
else
|
||||
{
|
||||
m_outputStream << ", " << utils::Keyword("effect") << "(" << utils::Number(std::to_string(currentEffectID)) << "), ";
|
||||
currentEffectID++;
|
||||
}
|
||||
|
||||
effect.postcondition().variable().printNameAsASPPredicate(m_outputStream);
|
||||
m_outputStream << ", ";
|
||||
effect.postcondition().value().printAsASPPredicate(m_outputStream);
|
||||
m_outputStream << ")." << std::endl;
|
||||
|
||||
currentEffectID++;
|
||||
});
|
||||
|
||||
m_outputStream << utils::Keyword("costs") << "(";
|
||||
operator_.printPredicateAsASP(m_outputStream);
|
||||
m_outputStream << ", " << operator_.costs() << ")." << std::endl;
|
||||
});
|
||||
|
||||
m_outputStream << std::endl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -210,7 +223,12 @@ void TranslatorASP::translateMutexes() const
|
||||
const auto mutexGroupID = std::to_string(currentMutexGroupID);
|
||||
currentMutexGroupID++;
|
||||
|
||||
m_outputStream << std::endl << utils::Keyword("mutexGroup") << "(" << utils::Number(mutexGroupID) << ")." << std::endl;
|
||||
m_outputStream
|
||||
<< std::endl
|
||||
<< utils::Keyword("mutexGroup") << "("
|
||||
<< utils::Keyword("mutexGroup") << "("
|
||||
<< utils::Number(mutexGroupID)
|
||||
<< "))." << std::endl;
|
||||
|
||||
const auto &facts = mutexGroup.facts();
|
||||
|
||||
@@ -230,10 +248,6 @@ void TranslatorASP::translateMutexes() const
|
||||
|
||||
void TranslatorASP::translateAxiomRules() const
|
||||
{
|
||||
if (!m_description.usesActionCosts())
|
||||
return;
|
||||
|
||||
m_outputStream << std::endl;
|
||||
m_outputStream << utils::Heading2("axiom rules");
|
||||
|
||||
const auto &axiomRules = m_description.axiomRules();
|
||||
@@ -246,14 +260,19 @@ void TranslatorASP::translateAxiomRules() const
|
||||
const auto axiomRuleID = std::to_string(currentAxiomRuleID);
|
||||
currentAxiomRuleID++;
|
||||
|
||||
m_outputStream << std::endl << utils::Keyword("axiomRule") << "(" << utils::Number(axiomRuleID) << ")." << std::endl;
|
||||
m_outputStream
|
||||
<< std::endl
|
||||
<< utils::Keyword("axiomRule") << "("
|
||||
<< utils::Keyword("axiomRule") << "("
|
||||
<< utils::Number(axiomRuleID)
|
||||
<< "))." << std::endl;
|
||||
|
||||
const auto &conditions = axiomRule.conditions();
|
||||
|
||||
std::for_each(conditions.cbegin(), conditions.cend(),
|
||||
[&](const auto &condition)
|
||||
{
|
||||
m_outputStream << utils::Keyword("condition") << "(" << utils::Keyword("axiomRule") << "(" << utils::Number(axiomRuleID) << "), ";
|
||||
m_outputStream << utils::Keyword("precondition") << "(" << utils::Keyword("axiomRule") << "(" << utils::Number(axiomRuleID) << "), ";
|
||||
condition.variable().printNameAsASPPredicate(m_outputStream);
|
||||
m_outputStream << ", ";
|
||||
condition.value().printAsASPPredicate(m_outputStream);
|
||||
|
@@ -55,7 +55,7 @@ Value Value::negated() const
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Value Value::fromSAS(utils::Parser &parser)
|
||||
Value Value::fromSAS(utils::Parser<> &parser)
|
||||
{
|
||||
const auto sasSign = parser.parse<std::string>();
|
||||
|
||||
@@ -75,12 +75,12 @@ Value Value::fromSAS(utils::Parser &parser)
|
||||
else if (sasSign == "NegatedAtom")
|
||||
value.m_sign = Value::Sign::Negative;
|
||||
else
|
||||
throw utils::ParserException(parser, "invalid value sign “" + sasSign + "”");
|
||||
throw utils::ParserException(parser.coordinate(), "invalid value sign “" + sasSign + "”");
|
||||
|
||||
try
|
||||
{
|
||||
parser.skipWhiteSpace();
|
||||
value.m_name = parser.getLine();
|
||||
value.m_name = parser.parseLine();
|
||||
|
||||
// Remove trailing ()
|
||||
if (value.m_name.find("()") != std::string::npos)
|
||||
@@ -91,7 +91,7 @@ Value Value::fromSAS(utils::Parser &parser)
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw utils::ParserException(parser, std::string("could not parse variable value (") + e.what() + ")");
|
||||
throw utils::ParserException(parser.coordinate(), std::string("could not parse variable value (") + e.what() + ")");
|
||||
}
|
||||
|
||||
return value;
|
||||
@@ -99,7 +99,7 @@ Value Value::fromSAS(utils::Parser &parser)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const Value &Value::referenceFromSAS(utils::Parser &parser, const Variable &variable)
|
||||
const Value &Value::referenceFromSAS(utils::Parser<> &parser, const Variable &variable)
|
||||
{
|
||||
const auto valueID = parser.parse<int>();
|
||||
|
||||
@@ -107,7 +107,7 @@ const Value &Value::referenceFromSAS(utils::Parser &parser, const Variable &vari
|
||||
return Value::Any;
|
||||
|
||||
if (valueID < 0 || static_cast<size_t>(valueID) >= variable.values().size())
|
||||
throw utils::ParserException(parser, "value index out of range (variable " + variable.name() + ", index " + std::to_string(valueID) + ")");
|
||||
throw utils::ParserException(parser.coordinate(), "value index out of range (variable " + variable.name() + ", index " + std::to_string(valueID) + ")");
|
||||
|
||||
return variable.values()[valueID];
|
||||
}
|
||||
|
@@ -24,11 +24,12 @@ Variable::Variable()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Variable Variable::fromSAS(utils::Parser &parser)
|
||||
Variable Variable::fromSAS(utils::Parser<> &parser)
|
||||
{
|
||||
Variable variable;
|
||||
|
||||
parser.expect<std::string>("begin_variable");
|
||||
parser.expect<std::string>("var");
|
||||
|
||||
variable.m_name = parser.parse<std::string>();
|
||||
variable.m_axiomLayer = parser.parse<int>();
|
||||
@@ -42,7 +43,7 @@ Variable Variable::fromSAS(utils::Parser &parser)
|
||||
|
||||
// <none of those> values are only allowed at the end
|
||||
if (j < numberOfValues - 1 && variable.m_values[j] == Value::None)
|
||||
throw utils::ParserException(parser, "<none of those> value must be the last value of a variable");
|
||||
throw utils::ParserException(parser.coordinate(), "<none of those> value must be the last value of a variable");
|
||||
}
|
||||
|
||||
parser.expect<std::string>("end_variable");
|
||||
@@ -54,17 +55,17 @@ Variable Variable::fromSAS(utils::Parser &parser)
|
||||
|
||||
void Variable::printNameAsASPPredicate(utils::LogStream &outputStream) const
|
||||
{
|
||||
outputStream << utils::Keyword("variable") << "(" << utils::escapeASP(m_name) << ")";
|
||||
outputStream << utils::Keyword("variable") << "(" << utils::Number(utils::escapeASP(m_name)) << ")";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const Variable &Variable::referenceFromSAS(utils::Parser &parser, const Variables &variables)
|
||||
const Variable &Variable::referenceFromSAS(utils::Parser<> &parser, const Variables &variables)
|
||||
{
|
||||
const auto variableID = parser.parse<size_t>();
|
||||
|
||||
if (variableID >= variables.size())
|
||||
throw utils::ParserException(parser, "variable index out of range (index " + std::to_string(variableID) + ")");
|
||||
throw utils::ParserException(parser.coordinate(), "variable index out of range (index " + std::to_string(variableID) + ")");
|
||||
|
||||
return variables[variableID];
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ VariableTransition::VariableTransition()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VariableTransition VariableTransition::fromSAS(utils::Parser &parser, const Variables &variables)
|
||||
VariableTransition VariableTransition::fromSAS(utils::Parser<> &parser, const Variables &variables)
|
||||
{
|
||||
VariableTransition variableTransition;
|
||||
|
||||
|
@@ -105,7 +105,7 @@ void Logger::logError(const std::string &message)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Logger::logError(const Parser::Coordinate &coordinate, const std::string &message)
|
||||
void Logger::logError(const StreamCoordinate &coordinate, const std::string &message)
|
||||
{
|
||||
m_errorStream
|
||||
<< Format(Color::White, FontWeight::Bold) << coordinate.sectionName << ":"
|
||||
@@ -119,15 +119,13 @@ void Logger::logError(const Parser::Coordinate &coordinate, const std::string &m
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Logger::logWarning(const Parser &parser, const std::string &message)
|
||||
void Logger::logWarning(const StreamCoordinate &coordinate, const std::string &message)
|
||||
{
|
||||
if (m_warningLevel == WarningLevel::Ignore)
|
||||
return;
|
||||
|
||||
if (m_warningLevel == WarningLevel::Error)
|
||||
throw ParserException(parser, message);
|
||||
|
||||
const auto coordinate = parser.coordinate();
|
||||
throw ParserException(coordinate, message);
|
||||
|
||||
m_errorStream
|
||||
<< Format(Color::White, FontWeight::Bold) << coordinate.sectionName << ":"
|
||||
|
@@ -1,621 +0,0 @@
|
||||
#include <plasp/utils/Parser.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <plasp/utils/ParserException.h>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Parser
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const std::istreambuf_iterator<char> Parser::EndOfFile = std::istreambuf_iterator<char>();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Parser::Parser()
|
||||
: m_isCaseSensitive{true}
|
||||
{
|
||||
std::setlocale(LC_NUMERIC, "C");
|
||||
|
||||
// Don’t skip whitespace
|
||||
m_stream.exceptions(std::istream::badbit);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Parser::Parser(std::string streamName, std::istream &istream)
|
||||
: Parser()
|
||||
{
|
||||
readStream(streamName, istream);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Parser::Parser(Parser &&other)
|
||||
: m_stream{std::move(other.m_stream)},
|
||||
m_streamDelimiters{std::move(other.m_streamDelimiters)},
|
||||
m_isCaseSensitive{other.m_isCaseSensitive}
|
||||
{
|
||||
other.m_isCaseSensitive = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Parser &Parser::operator=(Parser &&other)
|
||||
{
|
||||
m_stream = std::move(other.m_stream);
|
||||
m_streamDelimiters = std::move(other.m_streamDelimiters);
|
||||
m_isCaseSensitive = other.m_isCaseSensitive;
|
||||
|
||||
other.m_isCaseSensitive = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::readStream(std::string streamName, std::istream &istream)
|
||||
{
|
||||
// Store position of new section
|
||||
const auto position = m_stream.tellp();
|
||||
|
||||
m_streamDelimiters.push_back({position, streamName});
|
||||
|
||||
m_stream << istream.rdbuf();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::readFile(const boost::filesystem::path &path)
|
||||
{
|
||||
if (!boost::filesystem::is_regular_file(path))
|
||||
throw std::runtime_error("File does not exist: “" + path.string() + "”");
|
||||
|
||||
std::ifstream fileStream(path.string(), std::ios::in);
|
||||
|
||||
readStream(path.string(), fileStream);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::reset()
|
||||
{
|
||||
m_stream.clear();
|
||||
seek(std::ios::beg);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::seek(Position position)
|
||||
{
|
||||
m_stream.clear();
|
||||
m_stream.seekg(position);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Parser::Position Parser::position() const
|
||||
{
|
||||
return m_stream.tellg();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Parser::Coordinate Parser::coordinate() const
|
||||
{
|
||||
const auto currentPosition = position();
|
||||
|
||||
// Find current section
|
||||
auto currentFile = std::find_if(m_streamDelimiters.crbegin(), m_streamDelimiters.crend(),
|
||||
[&](const auto &fileDelimiter)
|
||||
{
|
||||
return currentPosition >= fileDelimiter.position;
|
||||
});
|
||||
|
||||
// If the parser is at the end of the stream, still count from the beginning of the last section
|
||||
if (currentFile == m_streamDelimiters.crend())
|
||||
currentFile = m_streamDelimiters.crbegin();
|
||||
|
||||
// Go back to beginning of section
|
||||
m_stream.clear();
|
||||
m_stream.seekg(currentFile->position);
|
||||
|
||||
size_t row = 1;
|
||||
size_t column = 1;
|
||||
|
||||
// Compute the coordinate character by character
|
||||
while (true)
|
||||
{
|
||||
if (currentPosition == -1 && atEndOfStream())
|
||||
break;
|
||||
else if (currentPosition >= 0 && position() >= currentPosition)
|
||||
break;
|
||||
|
||||
const auto character = currentCharacter();
|
||||
|
||||
if (character == '\n')
|
||||
{
|
||||
row++;
|
||||
column = 1;
|
||||
}
|
||||
else if (std::isblank(character) || std::isprint(character))
|
||||
column++;
|
||||
|
||||
m_stream.ignore(1);
|
||||
}
|
||||
|
||||
return {currentFile->sectionName, row, column};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::setCaseSensitive(bool isCaseSensitive)
|
||||
{
|
||||
m_isCaseSensitive = isCaseSensitive;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char Parser::currentCharacter() const
|
||||
{
|
||||
if (m_isCaseSensitive)
|
||||
return m_stream.peek();
|
||||
|
||||
return std::tolower(m_stream.peek());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Parser::atEndOfStream() const
|
||||
{
|
||||
return position() == -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::checkStream() const
|
||||
{
|
||||
if (atEndOfStream())
|
||||
throw ParserException(*this, "reading past end of file");
|
||||
|
||||
if (m_stream.fail())
|
||||
throw ParserException(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::advance()
|
||||
{
|
||||
checkStream();
|
||||
m_stream.ignore(1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::skipWhiteSpace()
|
||||
{
|
||||
return skipWhiteSpace(
|
||||
[](const auto character)
|
||||
{
|
||||
return std::isspace(character);
|
||||
});
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::skipLine()
|
||||
{
|
||||
checkStream();
|
||||
|
||||
while (currentCharacter() != '\n')
|
||||
advance();
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string Parser::getLine()
|
||||
{
|
||||
checkStream();
|
||||
|
||||
std::string value;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const auto character = currentCharacter();
|
||||
|
||||
advance();
|
||||
|
||||
if (character == '\n')
|
||||
break;
|
||||
else if (character == '\r')
|
||||
continue;
|
||||
|
||||
value.push_back(character);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
std::string Parser::parse<std::string>()
|
||||
{
|
||||
skipWhiteSpace();
|
||||
|
||||
std::string value;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const auto character = currentCharacter();
|
||||
|
||||
if (std::isspace(character))
|
||||
break;
|
||||
|
||||
value.push_back(character);
|
||||
advance();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
bool Parser::probe<std::string>(const std::string &expectedValue)
|
||||
{
|
||||
const auto previousPosition = position();
|
||||
|
||||
if (!std::iswspace(expectedValue.front()))
|
||||
skipWhiteSpace();
|
||||
|
||||
const auto match = std::find_if(expectedValue.cbegin(), expectedValue.cend(),
|
||||
[&](const auto &expectedCharacter)
|
||||
{
|
||||
const auto character = static_cast<char>(this->currentCharacter());
|
||||
|
||||
if (character != expectedCharacter)
|
||||
return true;
|
||||
|
||||
this->advance();
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
const auto differs = (match != expectedValue.cend());
|
||||
|
||||
if (!differs)
|
||||
return true;
|
||||
|
||||
seek(previousPosition);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
void Parser::expect<std::string>(const std::string &expectedValue)
|
||||
{
|
||||
if (!probe<std::string>(expectedValue))
|
||||
throw ParserException(*this, "expected “" + expectedValue + "”");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
char Parser::parse<char>()
|
||||
{
|
||||
const auto value = currentCharacter();
|
||||
|
||||
advance();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
bool Parser::probe<char>(const char &expectedValue)
|
||||
{
|
||||
if (currentCharacter() != expectedValue)
|
||||
return false;
|
||||
|
||||
advance();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
void Parser::expect<char>(const char &expectedValue)
|
||||
{
|
||||
if (!probe<char>(expectedValue))
|
||||
throw ParserException(*this, std::string("expected “") + expectedValue + "”");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t Parser::parseIntegerBody()
|
||||
{
|
||||
checkStream();
|
||||
|
||||
if (!std::isdigit(currentCharacter()))
|
||||
throw ParserException(*this, "could not parse integer value");
|
||||
|
||||
uint64_t value = 0;
|
||||
|
||||
while (!atEndOfStream())
|
||||
{
|
||||
const auto character = currentCharacter();
|
||||
|
||||
if (!std::isdigit(character))
|
||||
break;
|
||||
|
||||
value *= 10;
|
||||
value += character - '0';
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
int64_t Parser::parse<int64_t>()
|
||||
{
|
||||
skipWhiteSpace();
|
||||
|
||||
bool positive = probe('+') || !probe('-');
|
||||
|
||||
const auto value = parseIntegerBody();
|
||||
|
||||
return (positive ? value : -value);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
uint64_t Parser::parse<uint64_t>()
|
||||
{
|
||||
skipWhiteSpace();
|
||||
|
||||
if (currentCharacter() == '-')
|
||||
throw ParserException(*this, "expected unsigned integer, got signed one");
|
||||
|
||||
return parseIntegerBody();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
bool Parser::probe<int64_t>(const int64_t &expectedValue)
|
||||
{
|
||||
const auto previousPosition = position();
|
||||
const auto value = parse<int64_t>();
|
||||
|
||||
if (value == expectedValue)
|
||||
return true;
|
||||
|
||||
seek(previousPosition);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
bool Parser::probe<uint64_t>(const uint64_t &expectedValue)
|
||||
{
|
||||
const auto previousPosition = position();
|
||||
const auto value = parse<uint64_t>();
|
||||
|
||||
if (value == expectedValue)
|
||||
return true;
|
||||
|
||||
seek(previousPosition);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
void Parser::expect<int64_t>(const int64_t &expectedValue)
|
||||
{
|
||||
if (!probe<int64_t>(expectedValue))
|
||||
throw ParserException(*this, "expected “" + std::to_string(expectedValue) + "”");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
void Parser::expect<uint64_t>(const uint64_t &expectedValue)
|
||||
{
|
||||
if (!probe<uint64_t>(expectedValue))
|
||||
throw ParserException(*this, "expected “" + std::to_string(expectedValue) + "”");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
int32_t Parser::parse<int32_t>()
|
||||
{
|
||||
return static_cast<int32_t>(parse<int64_t>());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
uint32_t Parser::parse<uint32_t>()
|
||||
{
|
||||
return static_cast<uint32_t>(parse<uint64_t>());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
bool Parser::probe<int32_t>(const int32_t &expectedValue)
|
||||
{
|
||||
return probe<int64_t>(static_cast<int64_t>(expectedValue));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
bool Parser::probe<uint32_t>(const uint32_t &expectedValue)
|
||||
{
|
||||
return probe<uint64_t>(static_cast<uint64_t>(expectedValue));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
void Parser::expect<int32_t>(const int32_t &expectedValue)
|
||||
{
|
||||
expect<int64_t>(static_cast<int64_t>(expectedValue));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
void Parser::expect<uint32_t>(const uint32_t &expectedValue)
|
||||
{
|
||||
expect<uint64_t>(static_cast<uint64_t>(expectedValue));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
bool Parser::parse<bool>()
|
||||
{
|
||||
skipWhiteSpace();
|
||||
|
||||
if (probe('0'))
|
||||
return false;
|
||||
|
||||
if (probe('1'))
|
||||
return true;
|
||||
|
||||
throw ParserException(*this, "could not parse Boolean value");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<>
|
||||
void Parser::expect<bool>(const bool &expectedValue)
|
||||
{
|
||||
const auto value = parse<bool>();
|
||||
|
||||
if (value != expectedValue)
|
||||
throw ParserException(*this, "expected “" + std::to_string(expectedValue) + "”");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Parser::probeNumber()
|
||||
{
|
||||
const auto previousPosition = position();
|
||||
|
||||
skipWhiteSpace();
|
||||
|
||||
while (!std::iswspace(currentCharacter()))
|
||||
if (!std::isdigit(currentCharacter()))
|
||||
{
|
||||
seek(previousPosition);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Parser::removeComments(const std::string &startSequence, const std::string &endSequence, bool removeEnd)
|
||||
{
|
||||
const auto inPosition = m_stream.tellg();
|
||||
const auto outPosition = m_stream.tellp();
|
||||
|
||||
m_stream.seekg(0);
|
||||
|
||||
const auto removeRange =
|
||||
[&](const auto &start, const auto &end)
|
||||
{
|
||||
BOOST_ASSERT(start != -1);
|
||||
|
||||
m_stream.clear();
|
||||
m_stream.seekp(start);
|
||||
m_stream.seekg(start);
|
||||
|
||||
auto position = start;
|
||||
|
||||
while (end == -1 || position < end)
|
||||
{
|
||||
m_stream.ignore(1);
|
||||
|
||||
if (atEndOfStream())
|
||||
return;
|
||||
|
||||
m_stream.put(' ');
|
||||
position += static_cast<std::streamoff>(1);
|
||||
}
|
||||
};
|
||||
|
||||
while (!atEndOfStream())
|
||||
{
|
||||
Position startPosition = m_stream.tellg();
|
||||
|
||||
while (!atEndOfStream())
|
||||
{
|
||||
startPosition = m_stream.tellg();
|
||||
|
||||
if (probe(startSequence))
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
Position endPosition = m_stream.tellg();
|
||||
|
||||
while (!atEndOfStream())
|
||||
{
|
||||
endPosition = m_stream.tellg();
|
||||
|
||||
if (probe(endSequence))
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (removeEnd)
|
||||
endPosition = m_stream.tellg();
|
||||
|
||||
removeRange(startPosition, endPosition);
|
||||
}
|
||||
|
||||
m_stream.clear();
|
||||
|
||||
m_stream.seekg(inPosition);
|
||||
m_stream.seekp(outPosition);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
}
|
162
src/plasp/utils/Stream.cpp
Normal file
162
src/plasp/utils/Stream.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
#include <plasp/utils/Stream.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace plasp
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Stream
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Stream::Stream()
|
||||
{
|
||||
std::setlocale(LC_NUMERIC, "C");
|
||||
|
||||
// Don’t skip whitespace
|
||||
m_stream.exceptions(std::istream::badbit);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Stream::Stream(std::string streamName, std::istream &istream)
|
||||
{
|
||||
read(streamName, istream);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Stream::read(std::string streamName, std::istream &istream)
|
||||
{
|
||||
// Store position of new section
|
||||
const auto position = m_stream.tellp();
|
||||
|
||||
m_delimiters.push_back({position, streamName});
|
||||
|
||||
m_stream << istream.rdbuf();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Stream::read(const boost::filesystem::path &path)
|
||||
{
|
||||
if (!boost::filesystem::is_regular_file(path))
|
||||
throw std::runtime_error("File does not exist: “" + path.string() + "”");
|
||||
|
||||
std::ifstream fileStream(path.string(), std::ios::in);
|
||||
|
||||
read(path.string(), fileStream);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Stream::reset()
|
||||
{
|
||||
m_stream.clear();
|
||||
seek(0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Stream::seek(Position position)
|
||||
{
|
||||
m_stream.clear();
|
||||
m_stream.seekg(position);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typename Stream::Position Stream::position() const
|
||||
{
|
||||
return m_stream.tellg();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
StreamCoordinate Stream::coordinate() const
|
||||
{
|
||||
const auto currentPosition = position();
|
||||
|
||||
// Find current section
|
||||
auto currentFile = std::find_if(m_delimiters.crbegin(), m_delimiters.crend(),
|
||||
[&](const auto &fileDelimiter)
|
||||
{
|
||||
return currentPosition >= fileDelimiter.position;
|
||||
});
|
||||
|
||||
// If the parser is at the end of the stream, still count from the beginning of the last section
|
||||
if (currentFile == m_delimiters.crend())
|
||||
currentFile = m_delimiters.crbegin();
|
||||
|
||||
// Go back to beginning of section
|
||||
m_stream.clear();
|
||||
m_stream.seekg(currentFile->position);
|
||||
|
||||
size_t row = 1;
|
||||
size_t column = 1;
|
||||
|
||||
// Compute the coordinate character by character
|
||||
while (true)
|
||||
{
|
||||
if (currentPosition == -1 && atEnd())
|
||||
break;
|
||||
else if (currentPosition >= 0 && position() >= currentPosition)
|
||||
break;
|
||||
|
||||
const auto character = currentCharacter();
|
||||
|
||||
if (character == '\n')
|
||||
{
|
||||
row++;
|
||||
column = 1;
|
||||
}
|
||||
else if (std::isblank(character) || std::isprint(character))
|
||||
column++;
|
||||
|
||||
m_stream.ignore(1);
|
||||
}
|
||||
|
||||
return {currentFile->sectionName, row, column};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char Stream::currentCharacter() const
|
||||
{
|
||||
return m_stream.peek();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Stream::atEnd() const
|
||||
{
|
||||
return position() == -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Stream::check() const
|
||||
{
|
||||
if (atEnd())
|
||||
throw ParserException(coordinate(), "reading past end of file");
|
||||
|
||||
if (m_stream.fail())
|
||||
throw ParserException(coordinate());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Stream::advance()
|
||||
{
|
||||
check();
|
||||
m_stream.ignore(1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
}
|
@@ -6,10 +6,10 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TEST(UtilsTests, ParseSimple)
|
||||
TEST(UtilsTests, ParserParse)
|
||||
{
|
||||
std::stringstream s("identifier 5 \n-51\t 0 1 expected unexpected");
|
||||
plasp::utils::Parser p("input", s);
|
||||
std::stringstream s(" identifier 5 \n-51\t 0 1 100 200 -300 -400");
|
||||
plasp::utils::Parser<> p("input", s);
|
||||
|
||||
ASSERT_EQ(p.parse<std::string>(), "identifier");
|
||||
ASSERT_EQ(p.parse<size_t>(), 5u);
|
||||
@@ -17,20 +17,6 @@ TEST(UtilsTests, ParseSimple)
|
||||
ASSERT_EQ(p.parse<bool>(), false);
|
||||
ASSERT_EQ(p.parse<bool>(), true);
|
||||
|
||||
ASSERT_NO_THROW(p.expect<std::string>("expected"));
|
||||
ASSERT_THROW(p.expect<std::string>("expected"), plasp::utils::ParserException);
|
||||
|
||||
// TODO: test case-insensitive input
|
||||
// TODO: test probing
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TEST(UtilsTests, ParseUnsignedNumbers)
|
||||
{
|
||||
std::stringstream s("100 200 -300 -400");
|
||||
plasp::utils::Parser p("input", s);
|
||||
|
||||
ASSERT_EQ(p.parse<int>(), 100);
|
||||
ASSERT_EQ(p.parse<size_t>(), 200u);
|
||||
ASSERT_EQ(p.parse<int>(), -300);
|
||||
@@ -39,16 +25,119 @@ TEST(UtilsTests, ParseUnsignedNumbers)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TEST(UtilsTests, ParserExpect)
|
||||
{
|
||||
std::stringstream s(" identifier 5 \n-51\t 0 1 100 200 -300 -400");
|
||||
plasp::utils::Parser<> p("input", s);
|
||||
|
||||
ASSERT_NO_THROW(p.expect<std::string>("identifier"));
|
||||
ASSERT_NO_THROW(p.expect<size_t>(5u));
|
||||
ASSERT_NO_THROW(p.expect<int>(-51));
|
||||
ASSERT_NO_THROW(p.expect<bool>(false));
|
||||
ASSERT_NO_THROW(p.expect<bool>(true));
|
||||
|
||||
ASSERT_NO_THROW(p.expect<int>(100));
|
||||
ASSERT_NO_THROW(p.expect<size_t>(200u));
|
||||
ASSERT_NO_THROW(p.expect<int>(-300));
|
||||
ASSERT_THROW(p.expect<size_t>(-400), plasp::utils::ParserException);
|
||||
|
||||
p.seek(0);
|
||||
ASSERT_THROW(p.expect<std::string>("error"), plasp::utils::ParserException);
|
||||
|
||||
p.seek(14);
|
||||
ASSERT_THROW(p.expect<size_t>(6u), plasp::utils::ParserException);
|
||||
|
||||
p.seek(17);
|
||||
ASSERT_THROW(p.expect<int>(-50), plasp::utils::ParserException);
|
||||
|
||||
p.seek(24);
|
||||
ASSERT_THROW(p.expect<bool>(true), plasp::utils::ParserException);
|
||||
|
||||
p.seek(26);
|
||||
ASSERT_THROW(p.expect<bool>(false), plasp::utils::ParserException);
|
||||
|
||||
p.seek(28);
|
||||
ASSERT_THROW(p.expect<int>(101), plasp::utils::ParserException);
|
||||
|
||||
p.seek(31);
|
||||
ASSERT_THROW(p.expect<size_t>(201), plasp::utils::ParserException);
|
||||
|
||||
p.seek(34);
|
||||
ASSERT_THROW(p.expect<int>(-299), plasp::utils::ParserException);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TEST(UtilsTests, ParserTest)
|
||||
{
|
||||
std::stringstream s(" identifier 5 \n-51\t 0 1");
|
||||
plasp::utils::Parser<> p("input", s);
|
||||
|
||||
plasp::utils::Parser<>::Position pos;
|
||||
|
||||
pos = p.position();
|
||||
ASSERT_EQ(p.testAndReturn<std::string>("error"), false);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndReturn<std::string>("identifier"), true);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndSkip<std::string>("error"), false);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndSkip<std::string>("identifier"), true);
|
||||
ASSERT_EQ(p.position(), 12);
|
||||
|
||||
pos = p.position();
|
||||
ASSERT_EQ(p.testAndReturn<size_t>(6u), false);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndReturn<size_t>(5u), true);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndSkip<size_t>(6u), false);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndSkip<size_t>(5u), true);
|
||||
ASSERT_EQ(p.position(), 15);
|
||||
|
||||
pos = p.position();
|
||||
ASSERT_EQ(p.testAndReturn<int>(-50), false);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndReturn<int>(-51), true);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndSkip<int>(-50), false);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndSkip<int>(-51), true);
|
||||
ASSERT_EQ(p.position(), 22);
|
||||
|
||||
pos = p.position();
|
||||
ASSERT_EQ(p.testAndReturn<bool>(true), false);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndReturn<bool>(false), true);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndSkip<bool>(true), false);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndSkip<bool>(false), true);
|
||||
ASSERT_EQ(p.position(), 25);
|
||||
|
||||
pos = p.position();
|
||||
ASSERT_EQ(p.testAndReturn<bool>(false), false);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndReturn<bool>(true), true);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndSkip<bool>(false), false);
|
||||
ASSERT_EQ(p.position(), pos);
|
||||
ASSERT_EQ(p.testAndSkip<bool>(true), true);
|
||||
ASSERT_EQ(p.position(), 27);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TEST(UtilsTests, ParseEndOfFile)
|
||||
{
|
||||
std::stringstream s1("test");
|
||||
plasp::utils::Parser p1("input", s1);
|
||||
plasp::utils::Parser<> p1("input", s1);
|
||||
|
||||
ASSERT_NO_THROW(p1.expect<std::string>("test"));
|
||||
ASSERT_THROW(p1.parse<std::string>(), plasp::utils::ParserException);
|
||||
|
||||
std::stringstream s2("test1 test2 test3");
|
||||
plasp::utils::Parser p2("input", s2);
|
||||
plasp::utils::Parser<> p2("input", s2);
|
||||
|
||||
ASSERT_NO_THROW(p2.expect<std::string>("test1"));
|
||||
ASSERT_NO_THROW(p2.expect<std::string>("test2"));
|
||||
@@ -56,13 +145,13 @@ TEST(UtilsTests, ParseEndOfFile)
|
||||
ASSERT_THROW(p2.parse<std::string>(), plasp::utils::ParserException);
|
||||
|
||||
std::stringstream s3("-127");
|
||||
plasp::utils::Parser p3("input", s3);
|
||||
plasp::utils::Parser<> p3("input", s3);
|
||||
|
||||
p3.expect<int>(-127);
|
||||
ASSERT_THROW(p3.parse<int>(), plasp::utils::ParserException);
|
||||
|
||||
std::stringstream s4("128 -1023 -4095");
|
||||
plasp::utils::Parser p4("input", s4);
|
||||
plasp::utils::Parser<> p4("input", s4);
|
||||
|
||||
ASSERT_NO_THROW(p4.expect<size_t>(128));
|
||||
ASSERT_NO_THROW(p4.expect<int>(-1023));
|
||||
@@ -70,13 +159,13 @@ TEST(UtilsTests, ParseEndOfFile)
|
||||
ASSERT_THROW(p4.parse<int>(), plasp::utils::ParserException);
|
||||
|
||||
std::stringstream s5("0");
|
||||
plasp::utils::Parser p5("input", s5);
|
||||
plasp::utils::Parser<> p5("input", s5);
|
||||
|
||||
p5.expect<bool>(false);
|
||||
ASSERT_THROW(p5.parse<bool>(), plasp::utils::ParserException);
|
||||
|
||||
std::stringstream s6("0 1 0");
|
||||
plasp::utils::Parser p6("input", s6);
|
||||
plasp::utils::Parser<> p6("input", s6);
|
||||
|
||||
ASSERT_NO_THROW(p6.expect<bool>(false));
|
||||
ASSERT_NO_THROW(p6.expect<bool>(true));
|
||||
@@ -89,9 +178,11 @@ TEST(UtilsTests, ParseEndOfFile)
|
||||
TEST(UtilsTests, ParserPosition)
|
||||
{
|
||||
std::stringstream s("123 \n4\ntest1\n test2\ntest3 \ntest4\n\n\n\n");
|
||||
plasp::utils::Parser p("input", s);
|
||||
plasp::utils::Parser<> p("input", s);
|
||||
|
||||
plasp::utils::Parser::Coordinate c;
|
||||
const auto startPosition = p.position();
|
||||
|
||||
plasp::utils::StreamCoordinate c;
|
||||
|
||||
c = p.coordinate();
|
||||
ASSERT_EQ(c.row, 1u);
|
||||
@@ -170,7 +261,22 @@ TEST(UtilsTests, ParserPosition)
|
||||
c = p.coordinate();
|
||||
ASSERT_EQ(c.row, 10u);
|
||||
ASSERT_EQ(c.column, 1u);
|
||||
ASSERT_TRUE(p.atEndOfStream());
|
||||
ASSERT_TRUE(p.atEnd());
|
||||
|
||||
p.reset();
|
||||
ASSERT_EQ(p.position(), startPosition);
|
||||
ASSERT_FALSE(p.atEnd());
|
||||
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
p.advance();
|
||||
|
||||
ASSERT_EQ(p.position(), static_cast<std::istream::pos_type>(5));
|
||||
|
||||
p.seek(static_cast<std::istream::pos_type>(7));
|
||||
|
||||
ASSERT_EQ(p.position(), static_cast<std::istream::pos_type>(7));
|
||||
|
||||
ASSERT_NO_THROW(p.expect<std::string>("test1"));
|
||||
|
||||
// TODO: test parser with multiple sections
|
||||
}
|
||||
@@ -180,11 +286,11 @@ TEST(UtilsTests, ParserPosition)
|
||||
TEST(UtilsTests, ParserRemoveComments)
|
||||
{
|
||||
std::stringstream s1("; comment at beginning\ntest1; comment in between\ntest2; comment at end");
|
||||
plasp::utils::Parser p1("input", s1);
|
||||
plasp::utils::Parser<> p1("input", s1);
|
||||
|
||||
p1.removeComments(";", "\n", false);
|
||||
|
||||
plasp::utils::Parser::Coordinate c;
|
||||
plasp::utils::StreamCoordinate c;
|
||||
|
||||
ASSERT_NO_THROW(p1.expect<std::string>("test1"));
|
||||
|
||||
@@ -200,10 +306,10 @@ TEST(UtilsTests, ParserRemoveComments)
|
||||
|
||||
p1.skipWhiteSpace();
|
||||
|
||||
ASSERT_TRUE(p1.atEndOfStream());
|
||||
ASSERT_TRUE(p1.atEnd());
|
||||
|
||||
std::stringstream s2("test;");
|
||||
plasp::utils::Parser p2("input", s2);
|
||||
plasp::utils::Parser<> p2("input", s2);
|
||||
|
||||
p2.removeComments(";", "\n", false);
|
||||
|
||||
@@ -211,10 +317,10 @@ TEST(UtilsTests, ParserRemoveComments)
|
||||
|
||||
p2.skipWhiteSpace();
|
||||
|
||||
ASSERT_TRUE(p2.atEndOfStream());
|
||||
ASSERT_TRUE(p2.atEnd());
|
||||
|
||||
std::stringstream s3("/* comment at start */ test1 /* comment in between */ test2 /*");
|
||||
plasp::utils::Parser p3("input", s3);
|
||||
plasp::utils::Parser<> p3("input", s3);
|
||||
|
||||
p3.removeComments("/*", "*/", true);
|
||||
|
||||
@@ -223,7 +329,7 @@ TEST(UtilsTests, ParserRemoveComments)
|
||||
|
||||
p3.skipWhiteSpace();
|
||||
|
||||
ASSERT_TRUE(p3.atEndOfStream());
|
||||
ASSERT_TRUE(p3.atEnd());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
Reference in New Issue
Block a user