75 Commits

Author SHA1 Message Date
4a2882711d Version bump for release 3.0.2 RC 1. 2016-08-14 17:36:59 +02:00
08113c961a Continuously incrementing effect IDs, with a special identifier for unconditional effects. 2016-08-14 17:21:41 +02:00
e2da46e20a Updated change log with documentation of output format. 2016-08-14 16:37:31 +02:00
0cf44da917 Minor formatting. 2016-08-14 16:35:38 +02:00
d03638919a Added more detail to the command-line interface documentation. 2016-08-14 16:34:39 +02:00
f5d342a442 Minor formatting. 2016-08-14 16:33:11 +02:00
06cab2f098 Put command-line interface documentation in a separate documentation file. 2016-08-14 16:31:23 +02:00
9d67ae800d Put building instructions in a separate documentation file. 2016-08-14 16:27:43 +02:00
d2a1030320 Added link to output format to the readme file. 2016-08-14 16:23:28 +02:00
5c17d23606 Added list of supported feature requirements. 2016-08-14 16:15:43 +02:00
bc1759aedf Minor formatting. 2016-08-14 16:09:36 +02:00
b9aef10db3 Documented axiom rules. 2016-08-14 16:07:45 +02:00
bdb6ac9fba Changed output format of axiom rules. 2016-08-14 16:02:28 +02:00
4d5f935e82 Minor formatting. 2016-08-14 16:01:39 +02:00
d604e44dff Documented mutex groups. 2016-08-14 16:00:31 +02:00
2c37da4cb4 Clarification about variables’ value uniqueness. 2016-08-14 16:00:09 +02:00
741078c4fd Minor formatting. 2016-08-14 15:50:49 +02:00
e101cf2aab Documented action costs. 2016-08-14 15:49:34 +02:00
3dfae74468 Documented goal. 2016-08-14 15:47:49 +02:00
2363f42bc9 Minor clarification in the documentation concerning action sequences. 2016-08-14 15:46:12 +02:00
491454ca3c Extended introduction to the documentation. 2016-08-14 15:44:14 +02:00
562b2296e5 Documented initial state. 2016-08-14 15:39:25 +02:00
3535afb1e1 Minor clarification concerning constants and objects. 2016-08-14 15:31:23 +02:00
7a63e4abb9 Documented constants and objects. 2016-08-14 15:29:27 +02:00
2281cd1cd4 Documented actions. 2016-08-14 15:14:27 +02:00
4037b339e4 Changed keyword for conditions of conditional effects. 2016-08-14 15:14:13 +02:00
00c3140f3b Restructured output format documentation once more and documented variables. 2016-08-14 14:58:04 +02:00
0fb282d153 Changed output format of feature requirements. 2016-08-14 14:55:46 +02:00
7a73f99581 Updated change log with recent fixes in SAS output formatting. 2016-08-13 19:14:04 +02:00
bdd68f04e1 Minor cleanup in documentation. 2016-08-13 19:02:05 +02:00
a5a300b150 Documented constants and objects. 2016-08-13 18:59:11 +02:00
197cec923e Added introductory example to output format documentation. 2016-08-13 18:47:01 +02:00
c391a1f566 Removed unwanted newline in SAS output. 2016-08-13 18:44:18 +02:00
1727113a8b Documented types. 2016-08-13 18:07:17 +02:00
18ac959970 Restructured documentation of feature requirements and added an example. 2016-08-13 17:52:27 +02:00
d00c5bb753 Minor rephrasing in documentation. 2016-08-13 17:42:02 +02:00
ffcf07b935 Documented feature requirements. 2016-08-13 17:39:39 +02:00
042531abc3 Started documenting the unified output format. 2016-08-13 13:35:30 +02:00
4fc7355fba Removed unwanted newline. 2016-08-13 13:21:00 +02:00
c12be088c6 Updated change log with unified output format. 2016-08-13 11:12:38 +02:00
9c3cfe8f7b Dropped »meta« prefix of encoding file because there will only be meta encodings. 2016-08-13 11:10:29 +02:00
d4c168af30 Unified SAS and PDDL meta encodings. 2016-08-13 11:09:35 +02:00
f2d3aee662 Updated PDDL meta encoding to recent changes of output format. 2016-08-13 11:09:35 +02:00
340db244f6 Fixed bug in output format. 2016-08-13 04:04:28 +02:00
8969364f73 Fixed syntax error in output format. 2016-08-13 03:27:37 +02:00
b67168134b Made initial state definition consistent with unified output format. 2016-08-13 03:22:25 +02:00
97d33da686 Added effect ID as a placeholder (for conditional effects) for consistency with unified output format. 2016-08-13 03:17:48 +02:00
1f35bda3d2 Wrapped translated PDDL action definitions for usability in meta encodings. 2016-08-13 03:11:38 +02:00
6960e8a8c7 Wrapped translated PDDL constant definitions for usability in meta encodings. 2016-08-13 03:09:14 +02:00
b30cecd297 Turning translated PDDL predicates into unified variable format in rest of output format. 2016-08-13 03:08:05 +02:00
99fc6988a3 Renamed heading to »variables«. 2016-08-13 02:50:07 +02:00
cf022f9959 Started turning translated PDDL predicates into unified variable format. 2016-08-13 02:48:30 +02:00
0a1044743e Renamed meta predicate for simplicity. 2016-08-13 02:33:28 +02:00
94b204615b Wrapped translated PDDL type definitions for usability in meta encodings. 2016-08-13 02:32:27 +02:00
230c6dfc15 Made order of sections of translated SAS more uniform with PDDL. 2016-08-13 02:29:48 +02:00
8be67e7065 Updated SAS meta encoding to recent changes of output format. 2016-08-13 01:49:00 +02:00
378b2ae673 Wrapped translated SAS axiom rule definitions for usability in meta encodings. 2016-08-13 01:44:45 +02:00
36e517bd80 Wrapped translated SAS mutex group definitions for usability in meta encodings. 2016-08-13 01:42:18 +02:00
569b3d0c97 Wrapped translated SAS action definitions for usability in meta encodings. 2016-08-13 01:40:31 +02:00
daf68d24ab Added highlighting of variable names. 2016-08-13 01:39:49 +02:00
8a82f52100 Wrapped translated SAS variable definitions for usability in meta encodings. 2016-08-13 01:36:08 +02:00
d0864b9efe Extended parser tests. 2016-08-08 12:40:02 +02:00
18bd606262 Extended parser tests. 2016-08-07 16:46:48 +02:00
252f50108b Removed unnecessary file. 2016-08-07 16:22:26 +02:00
015c34fc2b Minor refactoring. 2016-08-03 00:33:20 +02:00
d7b47797df Made Stream members protected again. 2016-08-03 00:28:22 +02:00
544d4e0635 Major refactoring of underlying Parser class. 2016-08-02 20:33:49 +02:00
73c9d6c1f3 Checking that Parser initially is case-sensitive. 2016-06-22 09:14:01 +01:00
d9578b6f1c Testing Parser position with seek and advance. 2016-06-22 09:07:19 +01:00
b5e325cbee Testing Parser’s reset method. 2016-06-22 09:02:46 +01:00
234938349c Fixed incorrect seek positions. 2016-06-22 08:59:18 +01:00
9ed7277ec9 Fixed minor formatting issue with axiom rules. 2016-06-22 08:45:48 +01:00
dc87c09442 Merge branch 'master' of github.com:potassco/plasp into develop 2016-06-15 00:57:01 +02:00
00688765fd Fixed typos in readme file. 2016-06-15 00:56:17 +02:00
3702b72feb Version bump after release 3.0.1. 2016-06-15 00:18:09 +02:00
73 changed files with 1765 additions and 1202 deletions

View File

@@ -1,5 +1,16 @@
# Change Log # 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) ## 3.0.1 (2016-06-14)
Features: Features:

View File

@@ -6,8 +6,8 @@
`plasp` 3 is in early development and not intended for productive use yet. `plasp` 3 is in early development and not intended for productive use yet.
`plasp` 3 translates planning problem instances to ASP facts. `plasp` 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` 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. 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/). Alternatively, PDDL instances may first be translated to SAS, the output format of [Fast Downward](http://www.fast-downward.org/).
```bash ```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`. 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 $ clingo encodings/pddl-meta-sequential-incremental.lp instance.lp
``` ```
### Command-Line Interface ## Command-Line Interface
```bash ```bash
$ plasp [files] [options] $ plasp [files] [options]
``` ```
`[files]` may be omitted, in which case the input is read from `std::cin`. `plasp` automatically detects the language of the input program.
The `[options]` are listed below:
| **option** | **explanation** | See [command-line interface](doc/command-line-interface.md) for more detail.
|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `-l` [ `--language` ] | Specify the input language (`sas` or `pddl`). Omit for automatic detection. | ## Output Format
| `--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`). | `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 ## 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 See [building instructions](doc/building-instructions.md) for more detail.
$ 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
```
## Contributors ## Contributors

View File

@@ -66,7 +66,7 @@ int main(int argc, char **argv)
if (variablesMap.count("version")) 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; return EXIT_SUCCESS;
} }
@@ -104,9 +104,7 @@ int main(int argc, char **argv)
try try
{ {
plasp::utils::Parser parser; plasp::utils::Parser<plasp::utils::CaseInsensitiveParserPolicy> parser;
parser.setCaseSensitive(false);
if (variablesMap.count("input")) if (variablesMap.count("input"))
{ {
@@ -115,11 +113,11 @@ int main(int argc, char **argv)
std::for_each(inputFiles.cbegin(), inputFiles.cend(), std::for_each(inputFiles.cbegin(), inputFiles.cend(),
[&](const auto &inputFile) [&](const auto &inputFile)
{ {
parser.readFile(inputFile); parser.read(inputFile);
}); });
} }
else else
parser.readStream("std::cin", std::cin); parser.read("std::cin", std::cin);
const auto detectLanguage = const auto detectLanguage =
[&]() [&]()

View 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
```

View 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`). |

View 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
View 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.

View File

@@ -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.

View File

@@ -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.

View 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.

View File

@@ -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(); parser.skipWhiteSpace();
// SAS begins with "begin_version" // 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; return Language::Type::SAS;
} }
@@ -33,7 +32,7 @@ Language::Type detectLanguage(utils::Parser &parser)
} }
// PDDL contains sections starting with "(define" // 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); parser.seek(std::ios::beg);
return Language::Type::PDDL; return Language::Type::PDDL;

View File

@@ -5,6 +5,7 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <plasp/pddl/Parser.h>
#include <plasp/utils/Logger.h> #include <plasp/utils/Logger.h>
namespace plasp namespace plasp
@@ -22,20 +23,21 @@ class Context
{ {
public: public:
Context() = default; Context() = default;
~Context() = default;
explicit Context(utils::Parser &&parser) explicit Context(Parser &&otherParser)
: parser{std::move(parser)} : parser{std::move(otherParser)}
{ {
} }
explicit Context(utils::Logger &&logger) explicit Context(utils::Logger &&otherLogger)
: logger{std::move(logger)} : logger{std::move(otherLogger)}
{ {
} }
explicit Context(utils::Parser &&parser, utils::Logger &&logger) explicit Context(Parser &&otherParser, utils::Logger &&otherLogger)
: parser{std::move(parser)}, : parser{std::move(otherParser)},
logger{std::move(logger)} logger{std::move(otherLogger)}
{ {
} }
@@ -56,7 +58,7 @@ class Context
return *this; return *this;
} }
utils::Parser parser; Parser parser;
utils::Logger logger; utils::Logger logger;
}; };

View File

@@ -45,9 +45,9 @@ class Description
Context m_context; Context m_context;
utils::Parser::Position m_domainPosition; utils::Stream::Position m_domainPosition;
std::unique_ptr<Domain> m_domain; std::unique_ptr<Domain> m_domain;
utils::Parser::Position m_problemPosition; utils::Stream::Position m_problemPosition;
std::unique_ptr<Problem> m_problem; std::unique_ptr<Problem> m_problem;
}; };

View File

@@ -4,10 +4,11 @@
#include <plasp/pddl/Action.h> #include <plasp/pddl/Action.h>
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Expression.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/Constant.h>
#include <plasp/pddl/expressions/PredicateDeclaration.h> #include <plasp/pddl/expressions/PredicateDeclaration.h>
#include <plasp/pddl/expressions/PrimitiveType.h> #include <plasp/pddl/expressions/PrimitiveType.h>
#include <plasp/pddl/Requirement.h>
namespace plasp namespace plasp
{ {
@@ -68,19 +69,19 @@ class Domain
std::string m_name; std::string m_name;
utils::Parser::Position m_requirementsPosition; utils::Stream::Position m_requirementsPosition;
Requirements m_requirements; Requirements m_requirements;
utils::Parser::Position m_typesPosition; utils::Stream::Position m_typesPosition;
expressions::PrimitiveTypes m_types; expressions::PrimitiveTypes m_types;
utils::Parser::Position m_constantsPosition; utils::Stream::Position m_constantsPosition;
expressions::Constants m_constants; expressions::Constants m_constants;
utils::Parser::Position m_predicatesPosition; utils::Stream::Position m_predicatesPosition;
expressions::PredicateDeclarations m_predicates; 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; std::vector<std::unique_ptr<Action>> m_actions;
}; };

View File

@@ -3,7 +3,7 @@
#include <iostream> #include <iostream>
#include <plasp/utils/Parser.h> #include <plasp/pddl/Parser.h>
namespace plasp namespace plasp
{ {
@@ -16,7 +16,7 @@ namespace pddl
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline void skipSection(utils::Parser &parser) inline void skipSection(Parser &parser)
{ {
size_t openParentheses = 1; size_t openParentheses = 1;

View 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

View File

@@ -4,6 +4,7 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/InitialState.h> #include <plasp/pddl/InitialState.h>
#include <plasp/pddl/Parser.h>
#include <plasp/pddl/Requirement.h> #include <plasp/pddl/Requirement.h>
namespace plasp namespace plasp
@@ -61,18 +62,18 @@ class Problem
std::string m_name; 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; Requirements m_requirements;
utils::Parser::Position m_objectsPosition; utils::Stream::Position m_objectsPosition;
expressions::Constants m_objects; expressions::Constants m_objects;
utils::Parser::Position m_initialStatePosition; utils::Stream::Position m_initialStatePosition;
std::unique_ptr<InitialState> m_initialState; std::unique_ptr<InitialState> m_initialState;
utils::Parser::Position m_goalPosition; utils::Stream::Position m_goalPosition;
ExpressionPointer m_goal; ExpressionPointer m_goal;
}; };

View File

@@ -3,7 +3,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Identifier.h>
namespace plasp namespace plasp
{ {
@@ -57,8 +56,8 @@ AtPointer At::parse(Context &context, ExpressionContext &expressionContext,
const auto position = parser.position(); const auto position = parser.position();
if (!parser.probe<std::string>("(") if (!parser.testAndSkip<std::string>("(")
|| !parser.probeIdentifier("at", isIdentifier)) || !parser.testIdentifierAndSkip("at"))
{ {
parser.seek(position); parser.seek(position);
return nullptr; return nullptr;
@@ -68,9 +67,9 @@ AtPointer At::parse(Context &context, ExpressionContext &expressionContext,
const auto timePointPosition = parser.position(); const auto timePointPosition = parser.position();
if (parser.probeIdentifier("start", isIdentifier)) if (parser.testIdentifierAndSkip("start"))
timePoint = TimePointStart; timePoint = TimePointStart;
else if (parser.probeIdentifier("end", isIdentifier)) else if (parser.testIdentifierAndSkip("end"))
timePoint = TimePointEnd; timePoint = TimePointEnd;
else if (parser.probeNumber()) else if (parser.probeNumber())
{ {

View File

@@ -4,7 +4,6 @@
#include <plasp/pddl/ConsistencyException.h> #include <plasp/pddl/ConsistencyException.h>
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/expressions/Variable.h> #include <plasp/pddl/expressions/Variable.h>
namespace plasp namespace plasp
@@ -52,8 +51,8 @@ std::unique_ptr<Derived> Binary<Derived>::parse(Context &context,
const auto position = parser.position(); const auto position = parser.position();
if (!parser.probe<std::string>("(") if (!parser.testAndSkip<std::string>("(")
|| !parser.probeIdentifier(Derived::Identifier, isIdentifier)) || !parser.testIdentifierAndSkip(Derived::Identifier))
{ {
parser.seek(position); parser.seek(position);
return nullptr; return nullptr;

View File

@@ -2,7 +2,6 @@
#define __PLASP__PDDL__EXPRESSIONS__CONSTANT_H #define __PLASP__PDDL__EXPRESSIONS__CONSTANT_H
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/utils/Parser.h> #include <plasp/utils/Parser.h>
#include <plasp/utils/ParserException.h> #include <plasp/utils/ParserException.h>

View File

@@ -4,7 +4,6 @@
#include <plasp/pddl/ConsistencyException.h> #include <plasp/pddl/ConsistencyException.h>
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/expressions/Variable.h> #include <plasp/pddl/expressions/Variable.h>
namespace plasp namespace plasp
@@ -50,8 +49,8 @@ std::unique_ptr<Derived> NAry<Derived>::parse(Context &context,
const auto position = parser.position(); const auto position = parser.position();
if (!parser.probe<std::string>("(") if (!parser.testAndSkip<std::string>("(")
|| !parser.probeIdentifier(Derived::Identifier, isIdentifier)) || !parser.testIdentifierAndSkip(Derived::Identifier))
{ {
parser.seek(position); parser.seek(position);
return nullptr; return nullptr;
@@ -71,7 +70,7 @@ std::unique_ptr<Derived> NAry<Derived>::parse(Context &context,
} }
if (expression->m_arguments.empty()) 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>(")"); parser.expect<std::string>(")");

View File

@@ -3,7 +3,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Identifier.h>
namespace plasp namespace plasp
{ {
@@ -50,8 +49,8 @@ NotPointer Not::parse(Context &context, ExpressionContext &expressionContext,
const auto position = parser.position(); const auto position = parser.position();
if (!parser.probe<std::string>("(") if (!parser.testAndSkip<std::string>("(")
|| !parser.probeIdentifier("not", isIdentifier)) || !parser.testIdentifierAndSkip("not"))
{ {
parser.seek(position); parser.seek(position);
return nullptr; return nullptr;

View File

@@ -3,7 +3,6 @@
#include <plasp/pddl/ConsistencyException.h> #include <plasp/pddl/ConsistencyException.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/utils/ParserException.h> #include <plasp/utils/ParserException.h>
namespace plasp namespace plasp

View File

@@ -27,8 +27,8 @@ using AssignedVariables = std::vector<AssignedVariable>;
class AssignedVariable class AssignedVariable
{ {
public: public:
static AssignedVariable fromSAS(utils::Parser &parser, const Variables &variables); 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 Variable &variable);
public: public:
explicit AssignedVariable(const Variable &variable, const Value &value); explicit AssignedVariable(const Variable &variable, const Value &value);

View File

@@ -29,7 +29,7 @@ class AxiomRule
using Condition = AssignedVariable; using Condition = AssignedVariable;
using Conditions = AssignedVariables; using Conditions = AssignedVariables;
static AxiomRule fromSAS(utils::Parser &parser, const Variables &variables); static AxiomRule fromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
const Conditions &conditions() const; const Conditions &conditions() const;

View File

@@ -29,7 +29,7 @@ namespace sas
class Description class Description
{ {
public: public:
static Description fromParser(utils::Parser &&parser); static Description fromParser(utils::Parser<> &&parser);
static Description fromStream(std::istream &istream); static Description fromStream(std::istream &istream);
static Description fromFile(const boost::filesystem::path &path); static Description fromFile(const boost::filesystem::path &path);
@@ -45,19 +45,21 @@ class Description
bool usesAxiomRules() const; bool usesAxiomRules() const;
bool usesConditionalEffects() const; bool usesConditionalEffects() const;
bool hasRequirements() const;
private: private:
Description(); Description();
void parseContent(utils::Parser &parser); void parseContent(utils::Parser<> &parser);
void parseVersionSection(utils::Parser &parser) const; void parseVersionSection(utils::Parser<> &parser) const;
void parseMetricSection(utils::Parser &parser); void parseMetricSection(utils::Parser<> &parser);
void parseVariablesSection(utils::Parser &parser); void parseVariablesSection(utils::Parser<> &parser);
void parseMutexSection(utils::Parser &parser); void parseMutexSection(utils::Parser<> &parser);
void parseInitialStateSection(utils::Parser &parser); void parseInitialStateSection(utils::Parser<> &parser);
void parseGoalSection(utils::Parser &parser); void parseGoalSection(utils::Parser<> &parser);
void parseOperatorSection(utils::Parser &parser); void parseOperatorSection(utils::Parser<> &parser);
void parseAxiomSection(utils::Parser &parser); void parseAxiomSection(utils::Parser<> &parser);
bool m_usesActionCosts; bool m_usesActionCosts;

View File

@@ -29,7 +29,7 @@ class Effect
using Condition = AssignedVariable; using Condition = AssignedVariable;
using Conditions = AssignedVariables; 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: public:
const Conditions &conditions() const; const Conditions &conditions() const;

View File

@@ -21,7 +21,7 @@ class Goal
using Fact = AssignedVariable; using Fact = AssignedVariable;
using Facts = AssignedVariables; using Facts = AssignedVariables;
static Goal fromSAS(utils::Parser &parser, const Variables &variables); static Goal fromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
const Facts &facts() const; const Facts &facts() const;

View File

@@ -21,7 +21,7 @@ class InitialState
using Fact = AssignedVariable; using Fact = AssignedVariable;
using Facts = AssignedVariables; using Facts = AssignedVariables;
static InitialState fromSAS(utils::Parser &parser, const Variables &variables); static InitialState fromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
const Facts &facts() const; const Facts &facts() const;

View File

@@ -28,7 +28,7 @@ class MutexGroup
using Fact = AssignedVariable; using Fact = AssignedVariable;
using Facts = AssignedVariables; using Facts = AssignedVariables;
static MutexGroup fromSAS(utils::Parser &parser, const Variables &variables); static MutexGroup fromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
const Facts &facts() const; const Facts &facts() const;

View File

@@ -33,7 +33,7 @@ class Operator
using Condition = AssignedVariable; using Condition = AssignedVariable;
using Conditions = AssignedVariables; using Conditions = AssignedVariables;
static Operator fromSAS(utils::Parser &parser, const Variables &variables); static Operator fromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
void printPredicateAsASP(utils::LogStream &ostream) const; void printPredicateAsASP(utils::LogStream &ostream) const;

View File

@@ -22,7 +22,7 @@ namespace sas
class Predicate class Predicate
{ {
public: public:
static Predicate fromSAS(utils::Parser &parser); static Predicate fromSAS(utils::Parser<> &parser);
using Arguments = std::vector<std::string>; using Arguments = std::vector<std::string>;

View File

@@ -39,8 +39,8 @@ struct Value
static const Value Any; static const Value Any;
static const Value None; static const Value None;
static Value fromSAS(utils::Parser &parser); static Value fromSAS(utils::Parser<> &parser);
static const Value &referenceFromSAS(utils::Parser &parser, const Variable &variable); static const Value &referenceFromSAS(utils::Parser<> &parser, const Variable &variable);
public: public:
Value negated() const; Value negated() const;

View File

@@ -28,8 +28,8 @@ using Variables = std::vector<Variable>;
class Variable class Variable
{ {
public: public:
static Variable fromSAS(utils::Parser &parser); static Variable fromSAS(utils::Parser<> &parser);
static const Variable &referenceFromSAS(utils::Parser &parser, const Variables &variables); static const Variable &referenceFromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
void printNameAsASPPredicate(utils::LogStream &outputStream) const; void printNameAsASPPredicate(utils::LogStream &outputStream) const;

View File

@@ -26,7 +26,7 @@ using VariableTransitions = std::vector<VariableTransition>;
class VariableTransition class VariableTransition
{ {
public: public:
static VariableTransition fromSAS(utils::Parser &parser, const Variables &variables); static VariableTransition fromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
const Variable &variable() const; const Variable &variable() const;

View File

@@ -4,8 +4,8 @@
#include <string> #include <string>
#include <plasp/utils/LogStream.h> #include <plasp/utils/LogStream.h>
#include <plasp/utils/Parser.h>
#include <plasp/utils/ParserException.h> #include <plasp/utils/ParserException.h>
#include <plasp/utils/StreamCoordinate.h>
namespace plasp namespace plasp
{ {
@@ -44,8 +44,8 @@ class Logger
void setColorPolicy(LogStream::ColorPolicy colorPolicy); void setColorPolicy(LogStream::ColorPolicy colorPolicy);
void logError(const std::string &message); void logError(const std::string &message);
void logError(const Parser::Coordinate &coordinate, const std::string &message); void logError(const StreamCoordinate &coordinate, const std::string &message);
void logWarning(const Parser &parser, const std::string &message); void logWarning(const StreamCoordinate &parserCoordinate, const std::string &message);
private: private:
LogStream m_outputStream; LogStream m_outputStream;

View File

@@ -8,111 +8,194 @@
#include <boost/filesystem.hpp> #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 plasp
{ {
namespace utils namespace utils
{ {
template<typename Type>
struct Tag
{
};
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// Parser // Parser
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
class Parser template<class ParserPolicy = CaseSensitiveParserPolicy>
class Parser: public Stream, public ParserPolicy
{ {
public: template<class OtherParserPolicy>
using Position = std::stringstream::pos_type; friend class Parser;
struct Coordinate
{
std::string sectionName;
size_t row;
size_t column;
};
struct StreamDelimiter
{
Position position;
std::string sectionName;
};
public: public:
explicit Parser(); explicit Parser();
explicit Parser(std::string streamName, std::istream &istream); explicit Parser(std::string streamName, std::istream &istream);
// Forbid copy construction/assignment template<class OtherParser>
Parser(const Parser &other) = delete; Parser(OtherParser &&otherParser)
Parser &operator=(const Parser &other) = delete; {
m_stream = std::move(otherParser.m_stream);
Parser(Parser &&other); m_delimiters = std::move(otherParser.m_delimiters);
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;
void removeComments(const std::string &startSequence, const std::string &endSequence, bool removeEnd); void removeComments(const std::string &startSequence, const std::string &endSequence, bool removeEnd);
char currentCharacter() const;
template<typename Type> template<typename Type>
Type parse(); Type parse();
template<class CharacterPredicate, class WhiteSpacePredicate> template<typename Type>
std::string parseIdentifier(CharacterPredicate characterPredicate, WhiteSpacePredicate whiteSpacePredicate); bool testAndReturn(const Type &expectedValue);
template<class CharacterPredicate>
std::string parseIdentifier(CharacterPredicate characterPredicate);
template<typename Type> template<typename Type>
bool probe(const Type &expectedValue); bool testAndSkip(const Type &expectedValue);
template<class CharacterPredicate>
bool probeIdentifier(const std::string &identifier, CharacterPredicate characterPredicate);
bool probeNumber();
template<typename Type> template<typename Type>
void expect(const Type &expectedValue); void expect(const Type &expectedValue);
template<class WhiteSpacePredicate> std::string parseIdentifier();
void skipWhiteSpace(WhiteSpacePredicate whiteSpacePredicate); bool testIdentifierAndReturn(const std::string &identifier);
bool testIdentifierAndSkip(const std::string &identifier);
// TODO: remove
bool probeNumber();
std::string parseLine();
void skipWhiteSpace(); void skipWhiteSpace();
void skipLine(); void skipLine();
std::string getLine();
private: 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: bool testImpl(const std::string &expectedValue);
void checkStream() const; 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(); uint64_t parseIntegerBody();
mutable std::stringstream m_stream;
std::vector<StreamDelimiter> m_streamDelimiters;
bool m_isCaseSensitive;
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
template<class CharacterPredicate, class WhiteSpacePredicate> template<class ParserPolicy>
std::string Parser::parseIdentifier(CharacterPredicate characterPredicate, WhiteSpacePredicate whiteSpacePredicate) 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; std::string value;
@@ -120,7 +203,7 @@ std::string Parser::parseIdentifier(CharacterPredicate characterPredicate, White
{ {
const auto character = currentCharacter(); const auto character = currentCharacter();
if (!characterPredicate(character)) if (!ParserPolicy::isIdentifierCharacter(character))
return value; return value;
value.push_back(character); value.push_back(character);
@@ -130,33 +213,342 @@ std::string Parser::parseIdentifier(CharacterPredicate characterPredicate, White
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
template<class CharacterPredicate> template<class ParserPolicy>
std::string Parser::parseIdentifier(CharacterPredicate characterPredicate) bool Parser<ParserPolicy>::testIdentifierAndSkip(const std::string &expectedValue)
{ {
return parseIdentifier(characterPredicate, return testAndSkip(expectedValue) && !ParserPolicy::isIdentifierCharacter(currentCharacter());
[&](const auto character) }
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
bool Parser<ParserPolicy>::probeNumber()
{
const auto previousPosition = position();
skipWhiteSpace();
while (!ParserPolicy::isWhiteSpaceCharacter(currentCharacter()))
if (!std::isdigit(currentCharacter()))
{ {
return std::isspace(character); seek(previousPosition);
});
return false;
}
return true;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
template<class CharacterPredicate> template<class ParserPolicy>
bool Parser::probeIdentifier(const std::string &expectedValue, CharacterPredicate characterPredicate) std::string Parser<ParserPolicy>::parseLine()
{ {
return probe<std::string>(expectedValue) && !characterPredicate(currentCharacter()); std::string value;
}
//////////////////////////////////////////////////////////////////////////////////////////////////// while (true)
{
template<class WhiteSpacePredicate> const auto character = currentCharacter();
void Parser::skipWhiteSpace(WhiteSpacePredicate whiteSpacePredicate)
{
checkStream();
while (!atEndOfStream() && whiteSpacePredicate(currentCharacter()))
advance(); 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);
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -4,7 +4,7 @@
#include <exception> #include <exception>
#include <string> #include <string>
#include <plasp/utils/Parser.h> #include <plasp/utils/StreamCoordinate.h>
namespace plasp namespace plasp
{ {
@@ -20,18 +20,18 @@ namespace utils
class ParserException: public std::exception class ParserException: public std::exception
{ {
public: public:
explicit ParserException(const utils::Parser &parser) explicit ParserException(const StreamCoordinate &coordinate)
: ParserException(parser, "unspecified parser error") : ParserException(coordinate, "unspecified parser error")
{ {
} }
explicit ParserException(const utils::Parser &parser, const char *message) explicit ParserException(const StreamCoordinate &coordinate, const char *message)
: ParserException(parser, static_cast<std::string>(message)) : ParserException(coordinate, static_cast<std::string>(message))
{ {
} }
explicit ParserException(const utils::Parser &parser, const std::string &message) explicit ParserException(const StreamCoordinate &coordinate, const std::string &message)
: m_coordinate{parser.coordinate()}, : m_coordinate{coordinate},
m_message{message}, m_message{message},
m_plainMessage{m_coordinate.sectionName + ":" + std::to_string(m_coordinate.row) m_plainMessage{m_coordinate.sectionName + ":" + std::to_string(m_coordinate.row)
+ ":" + std::to_string(m_coordinate.column) + " " + m_message} + ":" + std::to_string(m_coordinate.column) + " " + m_message}
@@ -47,7 +47,7 @@ class ParserException: public std::exception
return m_plainMessage.c_str(); return m_plainMessage.c_str();
} }
const Parser::Coordinate &coordinate() const const StreamCoordinate &coordinate() const
{ {
return m_coordinate; return m_coordinate;
} }
@@ -58,7 +58,7 @@ class ParserException: public std::exception
} }
private: private:
Parser::Coordinate m_coordinate; StreamCoordinate m_coordinate;
std::string m_message; std::string m_message;
std::string m_plainMessage; std::string m_plainMessage;
}; };

View 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

View 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

View File

@@ -1,28 +1,25 @@
#ifndef __PLASP__PDDL__IDENTIFIER_H #ifndef __PLASP__UTILS__STREAM_COORDINATE_H
#define __PLASP__PDDL__IDENTIFIER_H #define __PLASP__UTILS__STREAM_COORDINATE_H
#include <cctype> #include <string>
namespace plasp namespace plasp
{ {
namespace pddl namespace utils
{ {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// Identifier // StreamCoordinate
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
const auto isIdentifier = struct StreamCoordinate
[](const auto character) {
{ std::string sectionName;
return character != '?' size_t row;
&& character != '(' size_t column;
&& character != ')' };
&& character != ';'
&& std::isgraph(character);
};
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -5,10 +5,8 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Domain.h> #include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/expressions/Type.h> #include <plasp/pddl/expressions/Type.h>
#include <plasp/utils/IO.h> #include <plasp/utils/IO.h>
#include <plasp/utils/ParserException.h>
namespace plasp namespace plasp
{ {
@@ -23,31 +21,33 @@ namespace pddl
void Action::parseDeclaration(Context &context, Domain &domain) void Action::parseDeclaration(Context &context, Domain &domain)
{ {
auto &parser = context.parser;
auto action = std::make_unique<Action>(Action()); 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"); parser.expect<std::string>(":parameters");
context.parser.expect<std::string>("("); parser.expect<std::string>("(");
ExpressionContext expressionContext(domain, action->m_parameters); ExpressionContext expressionContext(domain, action->m_parameters);
// Read parameters // Read parameters
expressions::Variable::parseTypedDeclarations(context, expressionContext); expressions::Variable::parseTypedDeclarations(context, expressionContext);
context.parser.expect<std::string>(")"); parser.expect<std::string>(")");
// Parse preconditions and effects // 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); action->m_precondition = parsePreconditionExpression(context, expressionContext);
else if (context.parser.probeIdentifier("effect", isIdentifier)) else if (parser.testIdentifierAndSkip("effect"))
action->m_effect = parseEffectExpression(context, expressionContext); action->m_effect = parseEffectExpression(context, expressionContext);
context.parser.skipWhiteSpace(); parser.skipWhiteSpace();
} }
// Store new action // Store new action

View File

@@ -44,7 +44,7 @@ Description Description::fromStream(std::istream &istream)
{ {
Description description; Description description;
description.m_context.parser.readStream("std::cin", istream); description.m_context.parser.read("std::cin", istream);
description.parse(); description.parse();
return description; return description;
@@ -56,7 +56,7 @@ Description Description::fromFile(const std::string &path)
{ {
Description description; Description description;
description.m_context.parser.readFile(path); description.m_context.parser.read(path);
description.parse(); description.parse();
return description; return description;
@@ -73,7 +73,7 @@ Description Description::fromFiles(const std::vector<std::string> &paths)
std::for_each(paths.cbegin(), paths.cend(), std::for_each(paths.cbegin(), paths.cend(),
[&](const auto &path) [&](const auto &path)
{ {
description.m_context.parser.readFile(path); description.m_context.parser.read(path);
}); });
description.parse(); description.parse();
@@ -126,7 +126,6 @@ void Description::parse()
{ {
auto &parser = m_context.parser; auto &parser = m_context.parser;
parser.setCaseSensitive(false);
parser.removeComments(";", "\n", false); parser.removeComments(";", "\n", false);
// First, determine the locations of domain and problem // First, determine the locations of domain and problem
@@ -155,7 +154,7 @@ void Description::findSections()
parser.skipWhiteSpace(); parser.skipWhiteSpace();
while (!parser.atEndOfStream()) while (!parser.atEnd())
{ {
const auto position = parser.position(); const auto position = parser.position();
@@ -163,20 +162,20 @@ void Description::findSections()
parser.expect<std::string>("define"); parser.expect<std::string>("define");
parser.expect<std::string>("("); parser.expect<std::string>("(");
if (parser.probe<std::string>("domain")) if (parser.testAndSkip<std::string>("domain"))
{ {
if (m_domainPosition != -1) 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; m_domainPosition = position;
parser.seek(position); parser.seek(position);
m_domain->findSections(); 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) 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)); m_problem = std::make_unique<Problem>(Problem(m_context, *m_domain));
@@ -188,7 +187,7 @@ void Description::findSections()
else else
{ {
const auto sectionIdentifier = parser.parse<std::string>(); 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(); m_context.parser.skipWhiteSpace();

View File

@@ -3,7 +3,6 @@
#include <algorithm> #include <algorithm>
#include <plasp/pddl/ConsistencyException.h> #include <plasp/pddl/ConsistencyException.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/IO.h> #include <plasp/pddl/IO.h>
#include <plasp/pddl/expressions/Constant.h> #include <plasp/pddl/expressions/Constant.h>
#include <plasp/pddl/expressions/PredicateDeclaration.h> #include <plasp/pddl/expressions/PredicateDeclaration.h>
@@ -43,7 +42,7 @@ void Domain::findSections()
parser.expect<std::string>("("); parser.expect<std::string>("(");
parser.expect<std::string>("domain"); parser.expect<std::string>("domain");
m_name = m_context.parser.parseIdentifier(isIdentifier); m_name = m_context.parser.parseIdentifier();
parser.expect<std::string>(")"); parser.expect<std::string>(")");
@@ -53,7 +52,7 @@ void Domain::findSections()
if (unique && sectionPosition != -1) if (unique && sectionPosition != -1)
{ {
parser.seek(value); parser.seek(value);
throw utils::ParserException(parser, "only one “:" + sectionName + "” section allowed"); throw utils::ParserException(parser.coordinate(), "only one “:" + sectionName + "” section allowed");
} }
sectionPosition = value; sectionPosition = value;
@@ -72,38 +71,38 @@ void Domain::findSections()
const auto sectionIdentifierPosition = parser.position(); const auto sectionIdentifierPosition = parser.position();
// Save the parser position of the individual sections for later parsing // 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); setSectionPosition("requirements", m_requirementsPosition, position, true);
else if (parser.probeIdentifier("types", isIdentifier)) else if (parser.testIdentifierAndSkip("types"))
setSectionPosition("types", m_typesPosition, position, true); setSectionPosition("types", m_typesPosition, position, true);
else if (parser.probeIdentifier("constants", isIdentifier)) else if (parser.testIdentifierAndSkip("constants"))
setSectionPosition("constants", m_constantsPosition, position, true); setSectionPosition("constants", m_constantsPosition, position, true);
else if (parser.probeIdentifier("predicates", isIdentifier)) else if (parser.testIdentifierAndSkip("predicates"))
setSectionPosition("predicates", m_predicatesPosition, position, true); setSectionPosition("predicates", m_predicatesPosition, position, true);
else if (parser.probeIdentifier("action", isIdentifier)) else if (parser.testIdentifierAndSkip("action"))
{ {
m_actionPositions.emplace_back(-1); m_actionPositions.emplace_back(-1);
setSectionPosition("action", m_actionPositions.back(), position); setSectionPosition("action", m_actionPositions.back(), position);
} }
else if (parser.probeIdentifier("functions", isIdentifier) else if (parser.testIdentifierAndSkip("functions")
|| parser.probeIdentifier("constraints", isIdentifier) || parser.testIdentifierAndSkip("constraints")
|| parser.probeIdentifier("durative-action", isIdentifier) || parser.testIdentifierAndSkip("durative-action")
|| parser.probeIdentifier("derived", isIdentifier)) || parser.testIdentifierAndSkip("derived"))
{ {
parser.seek(sectionIdentifierPosition); 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); parser.seek(sectionIdentifierPosition);
} }
else else
{ {
const auto sectionIdentifier = parser.parseIdentifier(isIdentifier); const auto sectionIdentifier = parser.parseIdentifier();
parser.seek(position); 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 // Skip section for now and parse it later
@@ -340,7 +339,7 @@ void Domain::parseTypeSection()
while (parser.currentCharacter() != ')') while (parser.currentCharacter() != ')')
{ {
if (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); expressions::PrimitiveType::parseTypedDeclaration(m_context, *this);

View File

@@ -3,7 +3,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Domain.h> #include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/IO.h> #include <plasp/pddl/IO.h>
#include <plasp/pddl/expressions/And.h> #include <plasp/pddl/expressions/And.h>
#include <plasp/pddl/expressions/Imply.h> #include <plasp/pddl/expressions/Imply.h>
@@ -49,12 +48,12 @@ ExpressionPointer parsePreconditionExpression(Context &context,
const auto expressionIdentifierPosition = parser.position(); const auto expressionIdentifierPosition = parser.position();
if (parser.probeIdentifier("forall", isIdentifier) if (parser.testIdentifierAndSkip("forall")
|| parser.probeIdentifier("preference", isIdentifier)) || parser.testIdentifierAndSkip("preference"))
{ {
// TODO: refactor // TODO: refactor
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
return expressions::Unsupported::parse(context); return expressions::Unsupported::parse(context);
@@ -89,32 +88,32 @@ ExpressionPointer parseExpression(Context &context, ExpressionContext &expressio
const auto expressionIdentifierPosition = parser.position(); const auto expressionIdentifierPosition = parser.position();
if (parser.probeIdentifier("exists", isIdentifier) if (parser.testIdentifierAndSkip("exists")
|| parser.probeIdentifier("forall", isIdentifier) || parser.testIdentifierAndSkip("forall")
|| parser.probeIdentifier("-", isIdentifier) || parser.testIdentifierAndSkip("-")
|| parser.probeIdentifier("=", isIdentifier) || parser.testIdentifierAndSkip("=")
|| parser.probeIdentifier("*", isIdentifier) || parser.testIdentifierAndSkip("*")
|| parser.probeIdentifier("+", isIdentifier) || parser.testIdentifierAndSkip("+")
|| parser.probeIdentifier("-", isIdentifier) || parser.testIdentifierAndSkip("-")
|| parser.probeIdentifier("/", isIdentifier) || parser.testIdentifierAndSkip("/")
|| parser.probeIdentifier(">", isIdentifier) || parser.testIdentifierAndSkip(">")
|| parser.probeIdentifier("<", isIdentifier) || parser.testIdentifierAndSkip("<")
|| parser.probeIdentifier("=", isIdentifier) || parser.testIdentifierAndSkip("=")
|| parser.probeIdentifier(">=", isIdentifier) || parser.testIdentifierAndSkip(">=")
|| parser.probeIdentifier("<=", isIdentifier)) || parser.testIdentifierAndSkip("<="))
{ {
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
return expressions::Unsupported::parse(context); return expressions::Unsupported::parse(context);
} }
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); 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(); const auto expressionIdentifierPosition = parser.position();
if (parser.probeIdentifier("forall", isIdentifier) if (parser.testIdentifierAndSkip("forall")
|| parser.probeIdentifier("when", isIdentifier)) || parser.testIdentifierAndSkip("when"))
{ {
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
return expressions::Unsupported::parse(context); return expressions::Unsupported::parse(context);
@@ -168,37 +167,39 @@ ExpressionPointer parseEffectBodyExpression(Context &context, ExpressionContext
const auto expressionIdentifierPosition = parser.position(); const auto expressionIdentifierPosition = parser.position();
if (parser.probeIdentifier("=", isIdentifier) if (parser.testIdentifierAndSkip("=")
|| parser.probeIdentifier("assign", isIdentifier) || parser.testIdentifierAndSkip("assign")
|| parser.probeIdentifier("scale-up", isIdentifier) || parser.testIdentifierAndSkip("scale-up")
|| parser.probeIdentifier("scale-down", isIdentifier) || parser.testIdentifierAndSkip("scale-down")
|| parser.probeIdentifier("increase", isIdentifier) || parser.testIdentifierAndSkip("increase")
|| parser.probeIdentifier("decrease", isIdentifier)) || parser.testIdentifierAndSkip("decrease"))
{ {
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
return expressions::Unsupported::parse(context); return expressions::Unsupported::parse(context);
} }
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); 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) ExpressionPointer parsePredicate(Context &context, ExpressionContext &expressionContext)
{ {
auto &parser = context.parser;
ExpressionPointer expression; ExpressionPointer expression;
if ((expression = expressions::Predicate::parse(context, expressionContext))) if ((expression = expressions::Predicate::parse(context, expressionContext)))
return expression; 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(); const auto position = parser.position();
if (!parser.probe<std::string>("(")) if (!parser.testAndSkip<std::string>("("))
return nullptr; return nullptr;
const auto expressionIdentifierPosition = parser.position(); const auto expressionIdentifierPosition = parser.position();
if (parser.probeIdentifier("=", isIdentifier)) if (parser.testIdentifierAndSkip("="))
{ {
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
return expressions::Unsupported::parse(context); return expressions::Unsupported::parse(context);

View File

@@ -2,7 +2,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/IO.h> #include <plasp/pddl/IO.h>
#include <plasp/pddl/Problem.h> #include <plasp/pddl/Problem.h>
#include <plasp/pddl/expressions/At.h> #include <plasp/pddl/expressions/At.h>
@@ -46,20 +45,20 @@ std::unique_ptr<InitialState> InitialState::parseDeclaration(Context &context,
const auto expressionIdentifierPosition = parser.position(); const auto expressionIdentifierPosition = parser.position();
if (parser.probeIdentifier("=", isIdentifier)) if (parser.testIdentifierAndSkip("="))
{ {
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
return expressions::Unsupported::parse(context); return expressions::Unsupported::parse(context);
} }
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); 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(); parser.skipWhiteSpace();

View File

@@ -4,7 +4,6 @@
#include <plasp/pddl/Domain.h> #include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/IO.h> #include <plasp/pddl/IO.h>
#include <plasp/pddl/expressions/Constant.h> #include <plasp/pddl/expressions/Constant.h>
#include <plasp/utils/IO.h> #include <plasp/utils/IO.h>
@@ -43,7 +42,7 @@ void Problem::findSections()
parser.expect<std::string>("("); parser.expect<std::string>("(");
parser.expect<std::string>("problem"); parser.expect<std::string>("problem");
m_name = parser.parseIdentifier(isIdentifier); m_name = parser.parseIdentifier();
parser.expect<std::string>(")"); parser.expect<std::string>(")");
@@ -53,7 +52,7 @@ void Problem::findSections()
if (unique && sectionPosition != -1) if (unique && sectionPosition != -1)
{ {
parser.seek(value); parser.seek(value);
throw utils::ParserException(parser, "only one “:" + sectionName + "” section allowed"); throw utils::ParserException(parser.coordinate(), "only one “:" + sectionName + "” section allowed");
} }
sectionPosition = value; sectionPosition = value;
@@ -71,34 +70,34 @@ void Problem::findSections()
const auto sectionIdentifierPosition = parser.position(); const auto sectionIdentifierPosition = parser.position();
// TODO: check order of the sections // TODO: check order of the sections
if (parser.probeIdentifier("domain", isIdentifier)) if (parser.testIdentifierAndSkip("domain"))
setSectionPosition("domain", m_domainPosition, position, true); setSectionPosition("domain", m_domainPosition, position, true);
else if (parser.probeIdentifier("requirements", isIdentifier)) else if (parser.testIdentifierAndSkip("requirements"))
setSectionPosition("requirements", m_requirementsPosition, position, true); setSectionPosition("requirements", m_requirementsPosition, position, true);
else if (parser.probeIdentifier("objects", isIdentifier)) else if (parser.testIdentifierAndSkip("objects"))
setSectionPosition("objects", m_objectsPosition, position, true); setSectionPosition("objects", m_objectsPosition, position, true);
else if (parser.probeIdentifier("init", isIdentifier)) else if (parser.testIdentifierAndSkip("init"))
setSectionPosition("init", m_initialStatePosition, position, true); setSectionPosition("init", m_initialStatePosition, position, true);
else if (parser.probeIdentifier("goal", isIdentifier)) else if (parser.testIdentifierAndSkip("goal"))
setSectionPosition("goal", m_goalPosition, position, true); setSectionPosition("goal", m_goalPosition, position, true);
else if (parser.probeIdentifier("constraints", isIdentifier) else if (parser.testIdentifierAndSkip("constraints")
|| parser.probeIdentifier("metric", isIdentifier) || parser.testIdentifierAndSkip("metric")
|| parser.probeIdentifier("length", isIdentifier)) || parser.testIdentifierAndSkip("length"))
{ {
parser.seek(sectionIdentifierPosition); 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); parser.seek(sectionIdentifierPosition);
} }
else else
{ {
const auto sectionIdentifier = parser.parseIdentifier(isIdentifier); const auto sectionIdentifier = parser.parseIdentifier();
parser.seek(position); 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 // Skip section for now and parse it later
@@ -201,10 +200,10 @@ void Problem::parseDomainSection()
parser.skipWhiteSpace(); parser.skipWhiteSpace();
const auto domainName = parser.parseIdentifier(isIdentifier); const auto domainName = parser.parseIdentifier();
if (m_domain.name() != domainName) 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>(")"); parser.expect<std::string>(")");
} }

View File

@@ -4,7 +4,6 @@
#include <boost/assign.hpp> #include <boost/assign.hpp>
#include <boost/bimap.hpp> #include <boost/bimap.hpp>
#include <plasp/pddl/Identifier.h>
#include <plasp/utils/IO.h> #include <plasp/utils/IO.h>
#include <plasp/utils/ParserException.h> #include <plasp/utils/ParserException.h>
@@ -84,17 +83,19 @@ Requirement::Requirement(Requirement::Type type)
Requirement Requirement::parse(Context &context) 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); const auto match = requirementTypesToPDDL.right.find(requirementName);
if (match == requirementTypesToPDDL.right.end()) 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; const auto requirementType = match->second;
if (requirementType == Requirement::Type::GoalUtilities) 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); return Requirement(match->second);
} }

View File

@@ -85,7 +85,10 @@ void TranslatorASP::translateTypes() const
if (types.empty()) if (types.empty())
{ {
m_outputStream << utils::Keyword("type") << "(object)." << std::endl; m_outputStream
<< utils::Keyword("type") << "("
<< utils::Keyword("type") << "(object))." << std::endl;
return; return;
} }
@@ -94,7 +97,10 @@ void TranslatorASP::translateTypes() const
{ {
const auto typeName = utils::escapeASP(type->name()); 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(); const auto &parentTypes = type->parentTypes();
@@ -108,9 +114,9 @@ void TranslatorASP::translateTypes() const
<< "(" << typeName << "), " << utils::Keyword("type") << "(" << typeName << "), " << utils::Keyword("type")
<< "(" << parentTypeName << "))." << std::endl << "(" << parentTypeName << "))." << std::endl
<< utils::Keyword("hasType") << "(" << utils::Variable("X") << ", " << utils::Keyword("has") << "(" << utils::Variable("X") << ", "
<< utils::Keyword("type") << "(" << parentTypeName << ")) :- " << utils::Keyword("type") << "(" << parentTypeName << ")) :- "
<< utils::Keyword("hasType") << "(" << utils::Variable("X") << ", " << utils::Keyword("has") << "(" << utils::Variable("X") << ", "
<< utils::Keyword("type") << "(" << typeName << "))." << std::endl; << utils::Keyword("type") << "(" << typeName << "))." << std::endl;
}); });
}); });
@@ -120,27 +126,59 @@ void TranslatorASP::translateTypes() const
void TranslatorASP::translatePredicates() const void TranslatorASP::translatePredicates() const
{ {
m_outputStream << utils::Heading2("predicates"); m_outputStream << utils::Heading2("variables");
const auto &predicates = m_description.domain().predicates(); 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(), std::for_each(predicates.cbegin(), predicates.cend(),
[&](const auto &predicate) [&](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()); 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(), std::for_each(actions.cbegin(), actions.cend(),
[&](const auto &action) [&](const auto &action)
{ {
// TODO: rename
const auto translateLiteral = 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) << "("; m_outputStream << std::endl << utils::Keyword(ruleHead) << "(";
printActionName(*action); printActionName(*action);
// TODO: implement conditional effects
if (enumerateEffects)
m_outputStream << ", " << utils::Keyword("effect") << "(unconditional)";
m_outputStream << ", "; m_outputStream << ", ";
this->translateLiteral(literal); this->translateLiteral(literal);
m_outputStream << ") :- "; m_outputStream << ") :- " << utils::Keyword("action") << "(";
printActionName(*action); printActionName(*action);
m_outputStream << "."; m_outputStream << ").";
}; };
m_outputStream << std::endl; m_outputStream << std::endl;
// Name // Name
m_outputStream << utils::Keyword("action") << "(";
printActionName(*action); printActionName(*action);
m_outputStream << ")";
this->translateVariablesBody(action->parameters()); this->translateVariablesBody(action->parameters());
@@ -225,7 +270,7 @@ void TranslatorASP::translateActions() const
if (effect.expressionType() == Expression::Type::Predicate if (effect.expressionType() == Expression::Type::Predicate
|| effect.expressionType() == Expression::Type::Not) || effect.expressionType() == Expression::Type::Not)
{ {
translateLiteral("postcondition", effect); translateLiteral("postcondition", effect, true);
} }
// Assuming a conjunction // Assuming a conjunction
else else
@@ -238,7 +283,7 @@ void TranslatorASP::translateActions() const
std::for_each(andExpression.arguments().cbegin(), andExpression.arguments().cend(), std::for_each(andExpression.arguments().cbegin(), andExpression.arguments().cend(),
[&](const auto *argument) [&](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()); const auto constantName = utils::escapeASP(constant->name());
m_outputStream << std::endl << utils::Keyword("constant") m_outputStream << std::endl
<< "(" << constantName << ")." << std::endl; << utils::Keyword("constant") << "("
<< utils::Keyword("constant") << "("
<< constantName
<< "))." << std::endl;
const auto *type = constant->type(); const auto *type = constant->type();
if (type != nullptr) if (type != nullptr)
{ {
m_outputStream << utils::Keyword("hasType") << "(" m_outputStream << utils::Keyword("has") << "("
<< utils::Keyword("constant") << "(" << constantName << "), " << utils::Keyword("constant") << "(" << constantName << "), "
<< utils::Keyword("type") << "(" << utils::escapeASP(type->name()) << "))." << std::endl; << utils::Keyword("type") << "(" << utils::escapeASP(type->name()) << "))." << std::endl;
} }
else else
{ {
m_outputStream << utils::Keyword("hasType") << "(" m_outputStream << utils::Keyword("has") << "("
<< utils::Keyword("constant") << "(" << constantName << "), " << utils::Keyword("constant") << "(" << constantName << "), "
<< utils::Keyword("type") << "(object))." << std::endl; << 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()); 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::Variable(utils::escapeASPVariable(variable.name())) << ", "
<< utils::Keyword("type") << "(" << utils::escapeASP(type.name()) << "))"; << utils::Keyword("type") << "(" << utils::escapeASP(type.name()) << "))";
} }
else else
{ {
m_outputStream << utils::Keyword("hasType") << "(" m_outputStream << utils::Keyword("has") << "("
<< utils::Variable(utils::escapeASPVariable(variable.name())) << ", " << utils::Variable(utils::escapeASPVariable(variable.name())) << ", "
<< utils::Keyword("type") << "(object))"; << utils::Keyword("type") << "(object))";
} }
@@ -343,8 +391,13 @@ void TranslatorASP::translateLiteral(const Expression &literal) const
// Translate single predicate // Translate single predicate
if (literal.expressionType() == Expression::Type::Predicate) if (literal.expressionType() == Expression::Type::Predicate)
{ {
this->translatePredicate(dynamic_cast<const expressions::Predicate &>(literal)); const auto &predicate = dynamic_cast<const expressions::Predicate &>(literal);
m_outputStream << ", " << utils::Keyword("true");
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 // Assuming that "not" expression may only contain a predicate
else if (literal.expressionType() == Expression::Type::Not) else if (literal.expressionType() == Expression::Type::Not)
@@ -352,8 +405,11 @@ void TranslatorASP::translateLiteral(const Expression &literal) const
const auto &notExpression = dynamic_cast<const expressions::Not &>(literal); const auto &notExpression = dynamic_cast<const expressions::Not &>(literal);
const auto &predicate = dynamic_cast<const expressions::Predicate &>(*notExpression.argument()); const auto &predicate = dynamic_cast<const expressions::Predicate &>(*notExpression.argument());
m_outputStream << utils::Keyword("variable") << "(";
this->translatePredicate(predicate); this->translatePredicate(predicate);
m_outputStream << ", " << utils::Keyword("false"); m_outputStream << "), " << utils::Keyword("value") << "(";
this->translatePredicate(predicate);
m_outputStream << ", " << utils::Keyword("false") << ")";
} }
else else
throw utils::TranslatorException("only primitive predicates and their negations supported as literals currently"); 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 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(); const auto &arguments = predicate.arguments();
if (arguments.empty()) if (arguments.empty())
{ {
m_outputStream << ")";
return; return;
} }
@@ -396,7 +451,7 @@ void TranslatorASP::translatePredicate(const expressions::Predicate &predicate)
throw utils::TranslatorException("only variables and constants supported in predicates currently"); 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 // Translate single predicate
if (fact->expressionType() == Expression::Type::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 // Assuming that "not" expression may only contain a predicate
else if (fact->expressionType() == Expression::Type::Not) else if (fact->expressionType() == Expression::Type::Not)
{ {

View File

@@ -37,7 +37,7 @@ ConstantPointer Constant::parseDeclaration(Context &context)
auto constant = std::make_unique<Constant>(Constant()); 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 != "-"); BOOST_ASSERT(constant->m_name != "-");
@@ -71,7 +71,7 @@ void Constant::parseTypedDeclaration(Context &context, Domain &domain, Constants
context.parser.skipWhiteSpace(); context.parser.skipWhiteSpace();
// Check for typing information // Check for typing information
if (!context.parser.probe('-')) if (!context.parser.testAndSkip<char>('-'))
return; return;
// If existing, parse and store parent type // If existing, parse and store parent type
@@ -113,7 +113,7 @@ void Constant::parseTypedDeclarations(Context &context, Domain &domain)
domain.checkRequirement(Requirement::Type::Typing); domain.checkRequirement(Requirement::Type::Typing);
// If no types are given, check that typing is not a requirement // If no types are given, check that typing is not a requirement
else if (domain.hasRequirement(Requirement::Type::Typing)) 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); problem.checkRequirement(Requirement::Type::Typing);
// If no types are given, check that typing is not a requirement // If no types are given, check that typing is not a requirement
else if (problem.hasRequirement(Requirement::Type::Typing)) 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) 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()); auto *constant = parseAndFind(constantName, domain.constants());
if (constant != nullptr) if (constant != nullptr)
return 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");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Constant *Constant::parseAndFind(Context &context, const Problem &problem) 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()); auto *constant = parseAndFind(constantName, problem.domain().constants());
@@ -177,7 +181,7 @@ Constant *Constant::parseAndFind(Context &context, const Problem &problem)
if (constant) if (constant)
return 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");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -13,6 +13,7 @@ namespace expressions
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: make static character string literal
const std::string Imply::Identifier = "imply"; const std::string Imply::Identifier = "imply";
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -3,7 +3,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Domain.h> #include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/Problem.h> #include <plasp/pddl/Problem.h>
#include <plasp/pddl/expressions/Constant.h> #include <plasp/pddl/expressions/Constant.h>
#include <plasp/pddl/expressions/Variable.h> #include <plasp/pddl/expressions/Variable.h>
@@ -34,13 +33,13 @@ PredicatePointer Predicate::parse(Context &context, ExpressionContext &expressio
const auto position = parser.position(); const auto position = parser.position();
if (!parser.probe<std::string>("(")) if (!parser.testAndSkip<std::string>("("))
{ {
parser.seek(position); parser.seek(position);
return nullptr; return nullptr;
} }
const auto predicateName = parser.parseIdentifier(isIdentifier); const auto predicateName = parser.parseIdentifier();
const auto &predicates = expressionContext.domain.predicates(); const auto &predicates = expressionContext.domain.predicates();
const auto matchingPredicate = std::find_if(predicates.cbegin(), predicates.cend(), 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(); const auto position = parser.position();
if (!parser.probe<std::string>("(")) if (!parser.testAndSkip<std::string>("("))
{ {
parser.seek(position); parser.seek(position);
return nullptr; return nullptr;
} }
const auto predicateName = parser.parseIdentifier(isIdentifier); const auto predicateName = parser.parseIdentifier();
const auto &predicates = problem.domain().predicates(); const auto &predicates = problem.domain().predicates();
const auto matchingPredicate = std::find_if(predicates.cbegin(), predicates.cend(), 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; predicate->m_name = predicateName;
context.parser.skipWhiteSpace(); parser.skipWhiteSpace();
while (context.parser.currentCharacter() != ')') while (parser.currentCharacter() != ')')
{ {
if (context.parser.currentCharacter() == '?') if (parser.currentCharacter() == '?')
throw utils::ParserException(context.parser, "variables not allowed in this context"); throw utils::ParserException(parser.coordinate(), "variables not allowed in this context");
// Parse objects and constants // Parse objects and constants
const auto *constant = Constant::parseAndFind(context, problem); const auto *constant = Constant::parseAndFind(context, problem);

View File

@@ -3,7 +3,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Domain.h> #include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/expressions/Constant.h> #include <plasp/pddl/expressions/Constant.h>
#include <plasp/pddl/expressions/Variable.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()); 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 // Flag predicate as correctly declared in the types section
predicate->setDeclared(); predicate->setDeclared();

View File

@@ -43,7 +43,7 @@ void PrimitiveType::parseDeclaration(Context &context, Domain &domain)
context.parser.skipWhiteSpace(); 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 match = std::find_if(types.cbegin(), types.cend(),
[&](const auto &primitiveType) [&](const auto &primitiveType)
@@ -76,7 +76,7 @@ void PrimitiveType::parseTypedDeclaration(Context &context, Domain &domain)
context.parser.skipWhiteSpace(); context.parser.skipWhiteSpace();
// Check for type inheritance // Check for type inheritance
if (!context.parser.probe('-')) if (!context.parser.testAndSkip<char>('-'))
return; return;
domain.checkRequirement(Requirement::Type::Typing); domain.checkRequirement(Requirement::Type::Typing);
@@ -102,14 +102,16 @@ void PrimitiveType::parseTypedDeclaration(Context &context, Domain &domain)
PrimitiveType *PrimitiveType::parseAndFind(Context &context, Domain &domain) PrimitiveType *PrimitiveType::parseAndFind(Context &context, Domain &domain)
{ {
auto &parser = context.parser;
auto &types = domain.types(); auto &types = domain.types();
context.parser.skipWhiteSpace(); parser.skipWhiteSpace();
const auto typeName = context.parser.parseIdentifier(isIdentifier); const auto typeName = parser.parseIdentifier();
if (typeName.empty()) 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 match = std::find_if(types.cbegin(), types.cend(),
[&](const auto &primitiveType) [&](const auto &primitiveType)
@@ -122,11 +124,11 @@ PrimitiveType *PrimitiveType::parseAndFind(Context &context, Domain &domain)
// Only "object" is allowed as an implicit type // Only "object" is allowed as an implicit type
if (typeName == "object" || typeName == "objects") 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)); types.emplace_back(std::make_unique<expressions::PrimitiveType>(typeName));
} }
else 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(); return types.back().get();
} }

View File

@@ -1,6 +1,5 @@
#include <plasp/pddl/expressions/Unsupported.h> #include <plasp/pddl/expressions/Unsupported.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/IO.h> #include <plasp/pddl/IO.h>
namespace plasp namespace plasp
@@ -24,9 +23,9 @@ UnsupportedPointer Unsupported::parse(Context &context)
parser.expect<std::string>("("); 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); skipSection(parser);

View File

@@ -7,7 +7,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Domain.h> #include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/expressions/Either.h> #include <plasp/pddl/expressions/Either.h>
#include <plasp/pddl/expressions/PrimitiveType.h> #include <plasp/pddl/expressions/PrimitiveType.h>
#include <plasp/pddl/expressions/Type.h> #include <plasp/pddl/expressions/Type.h>
@@ -36,13 +35,15 @@ Variable::Variable()
void Variable::parseDeclaration(Context &context, Variables &parameters) void Variable::parseDeclaration(Context &context, Variables &parameters)
{ {
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()); 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 // Check if variable of that name already exists in the current scope
const auto match = std::find_if(parameters.cbegin(), parameters.cend(), const auto match = std::find_if(parameters.cbegin(), parameters.cend(),
@@ -52,7 +53,7 @@ void Variable::parseDeclaration(Context &context, Variables &parameters)
}); });
if (match != parameters.cend()) 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 // Flag variable for potentially upcoming type declaration
variable->setDirty(); variable->setDirty();
@@ -75,7 +76,7 @@ void Variable::parseTypedDeclaration(Context &context, ExpressionContext &expres
parser.skipWhiteSpace(); parser.skipWhiteSpace();
// Check if the variable has a type declaration // Check if the variable has a type declaration
if (!parser.probe('-')) if (!parser.testAndSkip<char>('-'))
return; return;
const auto setType = const auto setType =
@@ -132,18 +133,20 @@ void Variable::parseTypedDeclarations(Context &context, ExpressionContext &expre
expressionContext.checkRequirement(Requirement::Type::Typing); expressionContext.checkRequirement(Requirement::Type::Typing);
// If no types are given, check that typing is not a requirement // If no types are given, check that typing is not a requirement
else if (expressionContext.hasRequirement(Requirement::Type::Typing)) 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) 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; const auto &variables = expressionContext.parameters;
@@ -154,7 +157,7 @@ const Variable *Variable::parseAndFind(Context &context, const ExpressionContext
}); });
if (match == variables.cend()) 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(); return match->get();
} }

View File

@@ -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; 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; AssignedVariable assignedVariable;

View File

@@ -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"); parser.expect<std::string>("begin_rule");

View File

@@ -28,10 +28,8 @@ Description::Description()
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Description Description::fromParser(utils::Parser &&parser) Description Description::fromParser(utils::Parser<> &&parser)
{ {
parser.setCaseSensitive(true);
Description description; Description description;
description.parseContent(parser); description.parseContent(parser);
@@ -42,8 +40,8 @@ Description Description::fromParser(utils::Parser &&parser)
Description Description::fromStream(std::istream &istream) Description Description::fromStream(std::istream &istream)
{ {
utils::Parser parser; utils::Parser<> parser;
parser.readStream("std::cin", istream); parser.read("std::cin", istream);
Description description; Description description;
description.parseContent(parser); description.parseContent(parser);
@@ -58,8 +56,8 @@ Description Description::fromFile(const boost::filesystem::path &path)
if (!boost::filesystem::is_regular_file(path)) if (!boost::filesystem::is_regular_file(path))
throw std::runtime_error("File does not exist: “" + path.string() + ""); throw std::runtime_error("File does not exist: “" + path.string() + "");
utils::Parser parser; utils::Parser<> parser;
parser.readFile(path); parser.read(path);
Description description; Description description;
description.parseContent(parser); 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); parseVersionSection(parser);
parseMetricSection(parser); parseMetricSection(parser);
@@ -168,27 +173,27 @@ void Description::parseContent(utils::Parser &parser)
parser.skipWhiteSpace(); parser.skipWhiteSpace();
if (!parser.atEndOfStream()) if (!parser.atEnd())
throw utils::ParserException(parser, "expected end of SAS description (perhaps, input contains two SAS descriptions?)"); 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"); parser.expect<std::string>("begin_version");
const auto formatVersion = parser.parse<size_t>(); const auto formatVersion = parser.parse<size_t>();
if (formatVersion != 3) 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"); parser.expect<std::string>("end_version");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Description::parseMetricSection(utils::Parser &parser) void Description::parseMetricSection(utils::Parser<> &parser)
{ {
parser.expect<std::string>("begin_metric"); 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>(); const auto numberOfVariables = parser.parse<size_t>();
m_variables.reserve(numberOfVariables); 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>(); const auto numberOfMutexGroups = parser.parse<size_t>();
m_mutexGroups.reserve(numberOfMutexGroups); 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)); 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)); 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>(); const auto numberOfOperators = parser.parse<size_t>();
m_operators.reserve(numberOfOperators); 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>(); const auto numberOfAxiomRules = parser.parse<size_t>();
m_axiomRules.reserve(numberOfAxiomRules); m_axiomRules.reserve(numberOfAxiomRules);

View File

@@ -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; Effect::Conditions conditions;

View File

@@ -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; Goal goal;

View File

@@ -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; InitialState initialState;

View File

@@ -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; MutexGroup mutexGroup;
@@ -29,7 +29,7 @@ MutexGroup MutexGroup::fromSAS(utils::Parser &parser, const Variables &variables
mutexGroup.m_facts.emplace_back(Fact::fromSAS(parser, variables)); mutexGroup.m_facts.emplace_back(Fact::fromSAS(parser, variables));
if (mutexGroup.m_facts[j].value() == Value::None) 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"); parser.expect<std::string>("end_mutex_group");

View File

@@ -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_; Operator operator_;

View File

@@ -18,7 +18,7 @@ namespace sas
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Predicate Predicate::fromSAS(utils::Parser &parser) Predicate Predicate::fromSAS(utils::Parser<> &parser)
{ {
Predicate predicate; Predicate predicate;
@@ -31,11 +31,12 @@ Predicate Predicate::fromSAS(utils::Parser &parser)
while (true) while (true)
{ {
// Parse arguments until reaching newline // Parse arguments until reaching newline
parser.skipWhiteSpace( // TODO: reimplement
/*parser.skipWhiteSpace(
[&](const auto character) [&](const auto character)
{ {
return character != '\n' && std::isspace(character); return character != '\n' && std::isspace(character);
}); });*/
if (parser.currentCharacter() == '\n') if (parser.currentCharacter() == '\n')
break; break;
@@ -46,7 +47,7 @@ Predicate Predicate::fromSAS(utils::Parser &parser)
} }
catch (const std::exception &e) 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; return predicate;

View File

@@ -23,13 +23,29 @@ TranslatorASP::TranslatorASP(const Description &description, utils::LogStream &o
void TranslatorASP::translate() const void TranslatorASP::translate() const
{ {
translateRequirements(); // TODO: remove double computation of requirements
translateInitialState(); if (m_description.hasRequirements())
translateGoal(); {
translateRequirements();
m_outputStream << std::endl;
}
translateVariables(); translateVariables();
m_outputStream << std::endl;
translateActions(); translateActions();
m_outputStream << std::endl;
translateMutexes(); translateMutexes();
translateAxiomRules();
if (m_description.usesAxiomRules())
{
m_outputStream << std::endl;
translateAxiomRules();
}
m_outputStream << std::endl;
translateInitialState();
m_outputStream << std::endl;
translateGoal();
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -39,15 +55,13 @@ void TranslatorASP::translateRequirements() const
m_outputStream << utils::Heading2("feature requirements") << std::endl; m_outputStream << utils::Heading2("feature requirements") << std::endl;
if (m_description.usesActionCosts()) 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()) 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()) if (m_description.usesConditionalEffects())
m_outputStream << utils::Keyword("requiresFeature") << "(conditionalEffects)." << std::endl; m_outputStream << utils::Keyword("requires") << "(" << utils::Keyword("feature") << "(conditionalEffects))." << std::endl;
m_outputStream << std::endl;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -67,8 +81,6 @@ void TranslatorASP::translateInitialState() const
fact.value().printAsASPPredicate(m_outputStream); fact.value().printAsASPPredicate(m_outputStream);
m_outputStream << ")." << std::endl; m_outputStream << ")." << std::endl;
}); });
m_outputStream << std::endl;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -88,8 +100,6 @@ void TranslatorASP::translateGoal() const
fact.value().printAsASPPredicate(m_outputStream); fact.value().printAsASPPredicate(m_outputStream);
m_outputStream << ")." << std::endl; m_outputStream << ")." << std::endl;
}); });
m_outputStream << std::endl;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -107,9 +117,9 @@ void TranslatorASP::translateVariables() const
BOOST_ASSERT(!values.empty()); BOOST_ASSERT(!values.empty());
m_outputStream << std::endl; m_outputStream << std::endl << utils::Keyword("variable") << "(";
variable.printNameAsASPPredicate(m_outputStream); variable.printNameAsASPPredicate(m_outputStream);
m_outputStream << "." << std::endl; m_outputStream << ")." << std::endl;
std::for_each(values.cbegin(), values.cend(), std::for_each(values.cbegin(), values.cend(),
[&](const auto &value) [&](const auto &value)
@@ -121,8 +131,6 @@ void TranslatorASP::translateVariables() const
m_outputStream << ")." << std::endl; m_outputStream << ")." << std::endl;
}); });
}); });
m_outputStream << std::endl;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -133,12 +141,14 @@ void TranslatorASP::translateActions() const
const auto &operators = m_description.operators(); const auto &operators = m_description.operators();
size_t currentEffectID = 0;
std::for_each(operators.cbegin(), operators.cend(), std::for_each(operators.cbegin(), operators.cend(),
[&](const auto &operator_) [&](const auto &operator_)
{ {
m_outputStream << std::endl; m_outputStream << std::endl << utils::Keyword("action") << "(";
operator_.printPredicateAsASP(m_outputStream); operator_.printPredicateAsASP(m_outputStream);
m_outputStream << "." << std::endl; m_outputStream << ")." << std::endl;
const auto &preconditions = operator_.preconditions(); const auto &preconditions = operator_.preconditions();
@@ -156,8 +166,6 @@ void TranslatorASP::translateActions() const
const auto &effects = operator_.effects(); const auto &effects = operator_.effects();
size_t currentEffectID = 0;
std::for_each(effects.cbegin(), effects.cend(), std::for_each(effects.cbegin(), effects.cend(),
[&](const auto &effect) [&](const auto &effect)
{ {
@@ -166,7 +174,8 @@ void TranslatorASP::translateActions() const
std::for_each(conditions.cbegin(), conditions.cend(), std::for_each(conditions.cbegin(), conditions.cend(),
[&](const auto &condition) [&](const auto &condition)
{ {
m_outputStream << utils::Keyword("effectCondition") << "("; // Conditions of conditional effects
m_outputStream << utils::Keyword("precondition") << "(";
operator_.printPredicateAsASP(m_outputStream); operator_.printPredicateAsASP(m_outputStream);
m_outputStream << ", " << utils::Keyword("effect") << "(" << utils::Number(std::to_string(currentEffectID)) << "), "; m_outputStream << ", " << utils::Keyword("effect") << "(" << utils::Number(std::to_string(currentEffectID)) << "), ";
condition.variable().printNameAsASPPredicate(m_outputStream); condition.variable().printNameAsASPPredicate(m_outputStream);
@@ -177,21 +186,25 @@ void TranslatorASP::translateActions() const
m_outputStream << utils::Keyword("postcondition") << "("; m_outputStream << utils::Keyword("postcondition") << "(";
operator_.printPredicateAsASP(m_outputStream); operator_.printPredicateAsASP(m_outputStream);
m_outputStream << ", " << utils::Keyword("effect") << "(" << utils::Number(std::to_string(currentEffectID)) << "), ";
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); effect.postcondition().variable().printNameAsASPPredicate(m_outputStream);
m_outputStream << ", "; m_outputStream << ", ";
effect.postcondition().value().printAsASPPredicate(m_outputStream); effect.postcondition().value().printAsASPPredicate(m_outputStream);
m_outputStream << ")." << std::endl; m_outputStream << ")." << std::endl;
currentEffectID++;
}); });
m_outputStream << utils::Keyword("costs") << "("; m_outputStream << utils::Keyword("costs") << "(";
operator_.printPredicateAsASP(m_outputStream); operator_.printPredicateAsASP(m_outputStream);
m_outputStream << ", " << operator_.costs() << ")." << std::endl; 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); const auto mutexGroupID = std::to_string(currentMutexGroupID);
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(); const auto &facts = mutexGroup.facts();
@@ -230,10 +248,6 @@ void TranslatorASP::translateMutexes() const
void TranslatorASP::translateAxiomRules() const void TranslatorASP::translateAxiomRules() const
{ {
if (!m_description.usesActionCosts())
return;
m_outputStream << std::endl;
m_outputStream << utils::Heading2("axiom rules"); m_outputStream << utils::Heading2("axiom rules");
const auto &axiomRules = m_description.axiomRules(); const auto &axiomRules = m_description.axiomRules();
@@ -246,14 +260,19 @@ void TranslatorASP::translateAxiomRules() const
const auto axiomRuleID = std::to_string(currentAxiomRuleID); const auto axiomRuleID = std::to_string(currentAxiomRuleID);
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(); const auto &conditions = axiomRule.conditions();
std::for_each(conditions.cbegin(), conditions.cend(), std::for_each(conditions.cbegin(), conditions.cend(),
[&](const auto &condition) [&](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); condition.variable().printNameAsASPPredicate(m_outputStream);
m_outputStream << ", "; m_outputStream << ", ";
condition.value().printAsASPPredicate(m_outputStream); condition.value().printAsASPPredicate(m_outputStream);

View File

@@ -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>(); const auto sasSign = parser.parse<std::string>();
@@ -75,12 +75,12 @@ Value Value::fromSAS(utils::Parser &parser)
else if (sasSign == "NegatedAtom") else if (sasSign == "NegatedAtom")
value.m_sign = Value::Sign::Negative; value.m_sign = Value::Sign::Negative;
else else
throw utils::ParserException(parser, "invalid value sign “" + sasSign + ""); throw utils::ParserException(parser.coordinate(), "invalid value sign “" + sasSign + "");
try try
{ {
parser.skipWhiteSpace(); parser.skipWhiteSpace();
value.m_name = parser.getLine(); value.m_name = parser.parseLine();
// Remove trailing () // Remove trailing ()
if (value.m_name.find("()") != std::string::npos) if (value.m_name.find("()") != std::string::npos)
@@ -91,7 +91,7 @@ Value Value::fromSAS(utils::Parser &parser)
} }
catch (const std::exception &e) 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; 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>(); const auto valueID = parser.parse<int>();
@@ -107,7 +107,7 @@ const Value &Value::referenceFromSAS(utils::Parser &parser, const Variable &vari
return Value::Any; return Value::Any;
if (valueID < 0 || static_cast<size_t>(valueID) >= variable.values().size()) 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]; return variable.values()[valueID];
} }

View File

@@ -24,11 +24,12 @@ Variable::Variable()
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Variable Variable::fromSAS(utils::Parser &parser) Variable Variable::fromSAS(utils::Parser<> &parser)
{ {
Variable variable; Variable variable;
parser.expect<std::string>("begin_variable"); parser.expect<std::string>("begin_variable");
parser.expect<std::string>("var");
variable.m_name = parser.parse<std::string>(); variable.m_name = parser.parse<std::string>();
variable.m_axiomLayer = parser.parse<int>(); 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 // <none of those> values are only allowed at the end
if (j < numberOfValues - 1 && variable.m_values[j] == Value::None) 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"); parser.expect<std::string>("end_variable");
@@ -54,17 +55,17 @@ Variable Variable::fromSAS(utils::Parser &parser)
void Variable::printNameAsASPPredicate(utils::LogStream &outputStream) const 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>(); const auto variableID = parser.parse<size_t>();
if (variableID >= variables.size()) 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]; return variables[variableID];
} }

View File

@@ -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; VariableTransition variableTransition;

View File

@@ -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 m_errorStream
<< Format(Color::White, FontWeight::Bold) << coordinate.sectionName << ":" << 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) if (m_warningLevel == WarningLevel::Ignore)
return; return;
if (m_warningLevel == WarningLevel::Error) if (m_warningLevel == WarningLevel::Error)
throw ParserException(parser, message); throw ParserException(coordinate, message);
const auto coordinate = parser.coordinate();
m_errorStream m_errorStream
<< Format(Color::White, FontWeight::Bold) << coordinate.sectionName << ":" << Format(Color::White, FontWeight::Bold) << coordinate.sectionName << ":"

View File

@@ -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");
// Dont 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
View File

@@ -0,0 +1,162 @@
#include <plasp/utils/Stream.h>
#include <fstream>
namespace plasp
{
namespace utils
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Stream
//
////////////////////////////////////////////////////////////////////////////////////////////////////
Stream::Stream()
{
std::setlocale(LC_NUMERIC, "C");
// Dont 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);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -6,10 +6,10 @@
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(UtilsTests, ParseSimple) TEST(UtilsTests, ParserParse)
{ {
std::stringstream s("identifier 5 \n-51\t 0 1 expected unexpected"); std::stringstream s(" identifier 5 \n-51\t 0 1 100 200 -300 -400");
plasp::utils::Parser p("input", s); plasp::utils::Parser<> p("input", s);
ASSERT_EQ(p.parse<std::string>(), "identifier"); ASSERT_EQ(p.parse<std::string>(), "identifier");
ASSERT_EQ(p.parse<size_t>(), 5u); 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>(), false);
ASSERT_EQ(p.parse<bool>(), true); 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<int>(), 100);
ASSERT_EQ(p.parse<size_t>(), 200u); ASSERT_EQ(p.parse<size_t>(), 200u);
ASSERT_EQ(p.parse<int>(), -300); 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) TEST(UtilsTests, ParseEndOfFile)
{ {
std::stringstream s1("test"); 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_NO_THROW(p1.expect<std::string>("test"));
ASSERT_THROW(p1.parse<std::string>(), plasp::utils::ParserException); ASSERT_THROW(p1.parse<std::string>(), plasp::utils::ParserException);
std::stringstream s2("test1 test2 test3"); 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>("test1"));
ASSERT_NO_THROW(p2.expect<std::string>("test2")); ASSERT_NO_THROW(p2.expect<std::string>("test2"));
@@ -56,13 +145,13 @@ TEST(UtilsTests, ParseEndOfFile)
ASSERT_THROW(p2.parse<std::string>(), plasp::utils::ParserException); ASSERT_THROW(p2.parse<std::string>(), plasp::utils::ParserException);
std::stringstream s3("-127"); std::stringstream s3("-127");
plasp::utils::Parser p3("input", s3); plasp::utils::Parser<> p3("input", s3);
p3.expect<int>(-127); p3.expect<int>(-127);
ASSERT_THROW(p3.parse<int>(), plasp::utils::ParserException); ASSERT_THROW(p3.parse<int>(), plasp::utils::ParserException);
std::stringstream s4("128 -1023 -4095"); 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<size_t>(128));
ASSERT_NO_THROW(p4.expect<int>(-1023)); ASSERT_NO_THROW(p4.expect<int>(-1023));
@@ -70,13 +159,13 @@ TEST(UtilsTests, ParseEndOfFile)
ASSERT_THROW(p4.parse<int>(), plasp::utils::ParserException); ASSERT_THROW(p4.parse<int>(), plasp::utils::ParserException);
std::stringstream s5("0"); std::stringstream s5("0");
plasp::utils::Parser p5("input", s5); plasp::utils::Parser<> p5("input", s5);
p5.expect<bool>(false); p5.expect<bool>(false);
ASSERT_THROW(p5.parse<bool>(), plasp::utils::ParserException); ASSERT_THROW(p5.parse<bool>(), plasp::utils::ParserException);
std::stringstream s6("0 1 0"); 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>(false));
ASSERT_NO_THROW(p6.expect<bool>(true)); ASSERT_NO_THROW(p6.expect<bool>(true));
@@ -89,9 +178,11 @@ TEST(UtilsTests, ParseEndOfFile)
TEST(UtilsTests, ParserPosition) TEST(UtilsTests, ParserPosition)
{ {
std::stringstream s("123 \n4\ntest1\n test2\ntest3 \ntest4\n\n\n\n"); 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(); c = p.coordinate();
ASSERT_EQ(c.row, 1u); ASSERT_EQ(c.row, 1u);
@@ -170,7 +261,22 @@ TEST(UtilsTests, ParserPosition)
c = p.coordinate(); c = p.coordinate();
ASSERT_EQ(c.row, 10u); ASSERT_EQ(c.row, 10u);
ASSERT_EQ(c.column, 1u); 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 // TODO: test parser with multiple sections
} }
@@ -180,11 +286,11 @@ TEST(UtilsTests, ParserPosition)
TEST(UtilsTests, ParserRemoveComments) TEST(UtilsTests, ParserRemoveComments)
{ {
std::stringstream s1("; comment at beginning\ntest1; comment in between\ntest2; comment at end"); 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); p1.removeComments(";", "\n", false);
plasp::utils::Parser::Coordinate c; plasp::utils::StreamCoordinate c;
ASSERT_NO_THROW(p1.expect<std::string>("test1")); ASSERT_NO_THROW(p1.expect<std::string>("test1"));
@@ -200,10 +306,10 @@ TEST(UtilsTests, ParserRemoveComments)
p1.skipWhiteSpace(); p1.skipWhiteSpace();
ASSERT_TRUE(p1.atEndOfStream()); ASSERT_TRUE(p1.atEnd());
std::stringstream s2("test;"); std::stringstream s2("test;");
plasp::utils::Parser p2("input", s2); plasp::utils::Parser<> p2("input", s2);
p2.removeComments(";", "\n", false); p2.removeComments(";", "\n", false);
@@ -211,10 +317,10 @@ TEST(UtilsTests, ParserRemoveComments)
p2.skipWhiteSpace(); p2.skipWhiteSpace();
ASSERT_TRUE(p2.atEndOfStream()); ASSERT_TRUE(p2.atEnd());
std::stringstream s3("/* comment at start */ test1 /* comment in between */ test2 /*"); 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); p3.removeComments("/*", "*/", true);
@@ -223,7 +329,7 @@ TEST(UtilsTests, ParserRemoveComments)
p3.skipWhiteSpace(); p3.skipWhiteSpace();
ASSERT_TRUE(p3.atEndOfStream()); ASSERT_TRUE(p3.atEnd());
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////