Add repeat rules

This commit is contained in:
Max Brunsfeld 2013-11-15 08:46:45 -08:00
parent 80acabb03e
commit 92e73a9e70
8 changed files with 96 additions and 12 deletions

View file

@ -24,6 +24,7 @@
125120A4183083BD00C9B56A /* arithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 125120A3183083BD00C9B56A /* arithmetic.cpp */; };
12D1369D18328C5A005F3369 /* item_spec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12D1369C18328C5A005F3369 /* item_spec.cpp */; };
12D136A1183570F5005F3369 /* pattern_spec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12D136A0183570F5005F3369 /* pattern_spec.cpp */; };
12D136A4183678A2005F3369 /* repeat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12D136A2183678A2005F3369 /* repeat.cpp */; };
12F9A64E182DD5FD00FAF50C /* spec_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12F9A64C182DD5FD00FAF50C /* spec_helper.cpp */; };
12F9A651182DD6BC00FAF50C /* grammar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12F9A64F182DD6BC00FAF50C /* grammar.cpp */; };
27A343CA69E17E0F9EBEDF1C /* pattern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27A340F3EEB184C040521323 /* pattern.cpp */; };
@ -143,6 +144,8 @@
12D1369C18328C5A005F3369 /* item_spec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = item_spec.cpp; path = spec/lr/item_spec.cpp; sourceTree = SOURCE_ROOT; };
12D1369E18342088005F3369 /* todo.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = todo.md; sourceTree = "<group>"; };
12D136A0183570F5005F3369 /* pattern_spec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pattern_spec.cpp; path = spec/rules/pattern_spec.cpp; sourceTree = SOURCE_ROOT; };
12D136A2183678A2005F3369 /* repeat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = repeat.cpp; sourceTree = "<group>"; };
12D136A3183678A2005F3369 /* repeat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = repeat.h; sourceTree = "<group>"; };
12E71794181D02A80051A649 /* specs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = specs; sourceTree = BUILT_PRODUCTS_DIR; };
12E71852181D081C0051A649 /* rules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rules.h; sourceTree = "<group>"; };
12F9A64C182DD5FD00FAF50C /* spec_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = spec_helper.cpp; path = spec/spec_helper.cpp; sourceTree = SOURCE_ROOT; };
@ -175,6 +178,9 @@
1213060D182C398300FCF928 /* choice.h */,
27A340F3EEB184C040521323 /* pattern.cpp */,
27A3438C4FA59A3882E8493B /* pattern.h */,
12D136A2183678A2005F3369 /* repeat.cpp */,
12D136A3183678A2005F3369 /* repeat.h */,
1251209A1830145300C9B56A /* rule.cpp */,
12130607182C374800FCF928 /* rule.h */,
12130612182C3A1700FCF928 /* seq.cpp */,
12130613182C3A1700FCF928 /* seq.h */,
@ -182,7 +188,6 @@
12130616182C3D2900FCF928 /* string.h */,
12130609182C389100FCF928 /* symbol.cpp */,
1213060A182C389100FCF928 /* symbol.h */,
1251209A1830145300C9B56A /* rule.cpp */,
);
path = rules;
sourceTree = "<group>";
@ -541,6 +546,7 @@
12F9A651182DD6BC00FAF50C /* grammar.cpp in Sources */,
12512093182F307C00C9B56A /* parse_table_spec.cpp in Sources */,
1213061F182C857100FCF928 /* item_set_spec.cpp in Sources */,
12D136A4183678A2005F3369 /* repeat.cpp in Sources */,
12130622182C85D300FCF928 /* item_set.cpp in Sources */,
12130605182C348F00FCF928 /* char.cpp in Sources */,
1213060B182C389100FCF928 /* symbol.cpp in Sources */,

View file

@ -101,5 +101,22 @@ Describe(Rules) {
{ rules::character('b'), rules::blank() }
})));
}
};
It(handles_repeats) {
rules::rule_ptr repeat = rules::repeat(rules::str("ab"));
AssertThat(
repeat->transitions(),
EqualsTransitionMap(TransitionMap<rules::Rule>({
{
rules::character('a'),
rules::seq({
rules::character('b'),
rules::choice({
repeat,
rules::blank()
})
})
}})));
}
};
};

View file

@ -15,7 +15,7 @@ using namespace igloo;
// Assertion helpers for transition maps
typedef TransitionMap<rules::Rule> rule_tmap;
typedef bool (* rule_tmap_comparator)(const rule_tmap::pair_type &, const rule_tmap::pair_type &);
EqualsContainerConstraint<rule_tmap, rule_tmap_comparator> EqualsTransitionMap(const rule_tmap &expected);
typedef bool (* rule_tmap_comparator)(const std::pair<rules::rule_ptr, rules::rule_ptr> &, const std::pair<rules::rule_ptr, rules::rule_ptr> &);
EqualsContainerConstraint<TransitionMap<rules::Rule>, rule_tmap_comparator> EqualsTransitionMap(const TransitionMap<rules::Rule> &expected);
#endif

View file

@ -9,5 +9,6 @@
#include "string.h"
#include "pattern.h"
#include "char.h"
#include "repeat.h"
#endif

View file

@ -41,21 +41,25 @@ namespace tree_sitter {
case '(':
next();
result = rule();
if (peek() == ')') {
if (peek() != ')')
error("mismatched parens");
else
next();
return result;
} else {
throw std::string("Invalid regex pattern: ") + input;
}
break;
case ')':
error("mismatched parens");
break;
case '\\':
next();
result = character(peek());
next();
break;
default:
result = character(peek());
next();
return result;
break;
}
return result;
}
void next() {
@ -70,6 +74,10 @@ namespace tree_sitter {
return position < length;
}
void error(const char *message) {
throw std::string("Invalid regex pattern '") + input + "': " + message;
}
const std::string input;
const size_t length;
int position;

30
src/rules/repeat.cpp Normal file
View file

@ -0,0 +1,30 @@
#include "blank.h"
#include "seq.h"
#include "choice.h"
#include "repeat.h"
#include "transition_map.h"
namespace tree_sitter {
namespace rules {
Repeat::Repeat(const rule_ptr content) : content(content) {}
rule_ptr repeat(const rule_ptr content) {
return std::make_shared<Repeat>(content);
}
TransitionMap<Rule> Repeat::transitions() const {
return content->transitions().map<Rule>([&](const rule_ptr &value) -> rule_ptr {
return seq({ value, choice({ repeat(content), blank() }) });
});
}
bool Repeat::operator==(const Rule &rule) const {
const Repeat *other = dynamic_cast<const Repeat *>(&rule);
return other && (*other->content == *content);
}
std::string Repeat::to_string() const {
return std::string("(repeat ") + content->to_string() + ")";
}
}
}

22
src/rules/repeat.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef __tree_sitter__repeat__
#define __tree_sitter__repeat__
#include "rule.h"
namespace tree_sitter {
namespace rules {
class Repeat : public Rule {
public:
Repeat(rule_ptr content);
TransitionMap<Rule> transitions() const;
bool operator==(const Rule& other) const;
std::string to_string() const;
private:
const rule_ptr content;
};
rule_ptr repeat(const rule_ptr content);
}
}
#endif

View file

@ -9,18 +9,18 @@
namespace tree_sitter {
template<typename MappedType>
class TransitionMap {
public:
typedef std::shared_ptr<const rules::Rule> rule_ptr;
typedef std::shared_ptr<const MappedType> mapped_ptr;
typedef std::pair<rule_ptr, mapped_ptr> pair_type;
typedef std::vector<pair_type> contents_type;
public:
static bool elements_equal(const pair_type &left, const pair_type &right) {
return (*left.first == *right.first) && (*left.second == *right.second);
}
TransitionMap() : contents(contents_type()) {};
TransitionMap(std::initializer_list<std::pair<rule_ptr, mapped_ptr>> pairs) : contents(pairs) {};
typedef typename contents_type::const_iterator const_iterator;