diff --git a/.gitignore b/.gitignore index e96f5dd8..3e0299c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.idea spec/run.out* TreeSitter.xcodeproj/project.xcworkspace TreeSitter.xcodeproj/xcuserdata diff --git a/TreeSitter.xcodeproj/project.pbxproj b/TreeSitter.xcodeproj/project.pbxproj index 08c57912..367b4085 100644 --- a/TreeSitter.xcodeproj/project.pbxproj +++ b/TreeSitter.xcodeproj/project.pbxproj @@ -13,8 +13,17 @@ 12130611182C3A1100FCF928 /* blank.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1213060F182C3A1100FCF928 /* blank.cpp */; }; 12130614182C3A1700FCF928 /* seq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12130612182C3A1700FCF928 /* seq.cpp */; }; 12130617182C3D2900FCF928 /* string.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12130615182C3D2900FCF928 /* string.cpp */; }; + 1213061B182C84DF00FCF928 /* item.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12130619182C84DF00FCF928 /* item.cpp */; }; + 1213061F182C857100FCF928 /* item_set_spec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1213061D182C857100FCF928 /* item_set_spec.cpp */; }; + 12130622182C85D300FCF928 /* item_set.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12130620182C85D300FCF928 /* item_set.cpp */; }; 1214930E181E200B008E9BDA /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 121492E9181E200B008E9BDA /* main.cpp */; }; 1214930F181E200B008E9BDA /* rules_spec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 121492EA181E200B008E9BDA /* rules_spec.cpp */; }; + 12512093182F307C00C9B56A /* parse_table_spec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12512092182F307C00C9B56A /* parse_table_spec.cpp */; }; + 1251209B1830145300C9B56A /* rule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1251209A1830145300C9B56A /* rule.cpp */; }; + 1251209D18303CFB00C9B56A /* rules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1251209C18303CFB00C9B56A /* rules.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 */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -30,7 +39,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 121306011829FAED00FCF928 /* spec_helper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = spec_helper.h; sourceTree = SOURCE_ROOT; }; 12130603182C348F00FCF928 /* char.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = char.cpp; sourceTree = ""; }; 12130604182C348F00FCF928 /* char.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = char.h; sourceTree = ""; }; 12130607182C374800FCF928 /* rule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rule.h; sourceTree = ""; }; @@ -44,6 +52,11 @@ 12130613182C3A1700FCF928 /* seq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = seq.h; sourceTree = ""; }; 12130615182C3D2900FCF928 /* string.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string.cpp; sourceTree = ""; }; 12130616182C3D2900FCF928 /* string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string.h; sourceTree = ""; }; + 12130619182C84DF00FCF928 /* item.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = item.cpp; sourceTree = ""; }; + 1213061A182C84DF00FCF928 /* item.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = item.h; sourceTree = ""; }; + 1213061D182C857100FCF928 /* item_set_spec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = item_set_spec.cpp; path = spec/lr/item_set_spec.cpp; sourceTree = SOURCE_ROOT; }; + 12130620182C85D300FCF928 /* item_set.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = item_set.cpp; sourceTree = ""; }; + 12130621182C85D300FCF928 /* item_set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = item_set.h; sourceTree = ""; }; 12149265181E200B008E9BDA /* igloo-tests_CXX_prefix.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = "igloo-tests_CXX_prefix.hxx"; sourceTree = ""; }; 12149266181E200B008E9BDA /* igloo-tests_CXX_prefix.hxx.gch */ = {isa = PBXFileReference; lastKnownFileType = file; path = "igloo-tests_CXX_prefix.hxx.gch"; sourceTree = ""; }; 12149267181E200B008E9BDA /* snowhouse-tests_CXX_prefix.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = "snowhouse-tests_CXX_prefix.hxx"; sourceTree = ""; }; @@ -117,9 +130,18 @@ 121492C6181E200B008E9BDA /* igloo_framework.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = igloo_framework.h; sourceTree = ""; }; 121492E9181E200B008E9BDA /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = spec/main.cpp; sourceTree = SOURCE_ROOT; }; 121492EA181E200B008E9BDA /* rules_spec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = rules_spec.cpp; path = spec/rules_spec.cpp; sourceTree = SOURCE_ROOT; }; + 12512092182F307C00C9B56A /* parse_table_spec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = parse_table_spec.cpp; path = spec/lr/parse_table_spec.cpp; sourceTree = SOURCE_ROOT; }; + 1251209A1830145300C9B56A /* rule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rule.cpp; sourceTree = ""; }; + 1251209C18303CFB00C9B56A /* rules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rules.cpp; sourceTree = ""; }; 12C344421822F27700B07BE3 /* transition_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = transition_map.h; sourceTree = ""; }; 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 = ""; }; + 12F9A64C182DD5FD00FAF50C /* spec_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = spec_helper.cpp; path = spec/spec_helper.cpp; sourceTree = SOURCE_ROOT; }; + 12F9A64D182DD5FD00FAF50C /* spec_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = spec_helper.h; path = spec/spec_helper.h; sourceTree = SOURCE_ROOT; }; + 12F9A64F182DD6BC00FAF50C /* grammar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = grammar.cpp; sourceTree = ""; }; + 12F9A650182DD6BC00FAF50C /* grammar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = grammar.h; sourceTree = ""; }; + 27A340F3EEB184C040521323 /* Pattern.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Pattern.cpp; sourceTree = ""; }; + 27A3438C4FA59A3882E8493B /* Pattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pattern.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -142,17 +164,41 @@ 12130604182C348F00FCF928 /* char.h */, 1213060C182C398300FCF928 /* choice.cpp */, 1213060D182C398300FCF928 /* choice.h */, + 27A340F3EEB184C040521323 /* Pattern.cpp */, + 27A3438C4FA59A3882E8493B /* Pattern.h */, 12130607182C374800FCF928 /* rule.h */, 12130612182C3A1700FCF928 /* seq.cpp */, 12130613182C3A1700FCF928 /* seq.h */, - 12130609182C389100FCF928 /* symbol.cpp */, - 1213060A182C389100FCF928 /* symbol.h */, 12130615182C3D2900FCF928 /* string.cpp */, 12130616182C3D2900FCF928 /* string.h */, + 12130609182C389100FCF928 /* symbol.cpp */, + 1213060A182C389100FCF928 /* symbol.h */, + 1251209A1830145300C9B56A /* rule.cpp */, ); path = rules; sourceTree = ""; }; + 12130618182C84B700FCF928 /* lr */ = { + isa = PBXGroup; + children = ( + 12130619182C84DF00FCF928 /* item.cpp */, + 1213061A182C84DF00FCF928 /* item.h */, + 12130620182C85D300FCF928 /* item_set.cpp */, + 12130621182C85D300FCF928 /* item_set.h */, + ); + path = lr; + sourceTree = ""; + }; + 1213061C182C854F00FCF928 /* lr */ = { + isa = PBXGroup; + children = ( + 1213061D182C857100FCF928 /* item_set_spec.cpp */, + 12512092182F307C00C9B56A /* parse_table_spec.cpp */, + ); + name = lr; + path = spec/lr; + sourceTree = ""; + }; 1214925C181E200B008E9BDA /* externals */ = { isa = PBXGroup; children = ( @@ -364,7 +410,11 @@ 12E71701181D01890051A649 /* src */ = { isa = PBXGroup; children = ( + 12F9A64F182DD6BC00FAF50C /* grammar.cpp */, + 12F9A650182DD6BC00FAF50C /* grammar.h */, + 12130618182C84B700FCF928 /* lr */, 12130602182C344400FCF928 /* rules */, + 1251209C18303CFB00C9B56A /* rules.cpp */, 12E71852181D081C0051A649 /* rules.h */, 12C344421822F27700B07BE3 /* transition_map.h */, ); @@ -383,9 +433,11 @@ isa = PBXGroup; children = ( 1214925C181E200B008E9BDA /* externals */, + 1213061C182C854F00FCF928 /* lr */, 121492E9181E200B008E9BDA /* main.cpp */, 121492EA181E200B008E9BDA /* rules_spec.cpp */, - 121306011829FAED00FCF928 /* spec_helper.h */, + 12F9A64C182DD5FD00FAF50C /* spec_helper.cpp */, + 12F9A64D182DD5FD00FAF50C /* spec_helper.h */, ); name = spec; path = Specs; @@ -443,12 +495,21 @@ files = ( 12130614182C3A1700FCF928 /* seq.cpp in Sources */, 1214930F181E200B008E9BDA /* rules_spec.cpp in Sources */, + 1213061B182C84DF00FCF928 /* item.cpp in Sources */, + 1251209D18303CFB00C9B56A /* rules.cpp in Sources */, 12130617182C3D2900FCF928 /* string.cpp in Sources */, 12130611182C3A1100FCF928 /* blank.cpp in Sources */, 1213060E182C398300FCF928 /* choice.cpp in Sources */, + 12F9A64E182DD5FD00FAF50C /* spec_helper.cpp in Sources */, 1214930E181E200B008E9BDA /* main.cpp in Sources */, + 12F9A651182DD6BC00FAF50C /* grammar.cpp in Sources */, + 12512093182F307C00C9B56A /* parse_table_spec.cpp in Sources */, + 1213061F182C857100FCF928 /* item_set_spec.cpp in Sources */, + 12130622182C85D300FCF928 /* item_set.cpp in Sources */, 12130605182C348F00FCF928 /* char.cpp in Sources */, 1213060B182C389100FCF928 /* symbol.cpp in Sources */, + 1251209B1830145300C9B56A /* rule.cpp in Sources */, + 27A343CA69E17E0F9EBEDF1C /* Pattern.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -458,12 +519,14 @@ 12E716FE181D010E0051A649 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + GCC_VERSION = ""; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, spec/externals/igloo, src/externals/boost, ); + STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = dynamic; USER_HEADER_SEARCH_PATHS = "src/externals/boost spec/externals/igloo"; }; name = Debug; @@ -471,12 +534,14 @@ 12E716FF181D010E0051A649 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + GCC_VERSION = ""; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, spec/externals/igloo, src/externals/boost, ); + STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = dynamic; USER_HEADER_SEARCH_PATHS = "src/externals/boost spec/externals/igloo"; }; name = Release; @@ -485,7 +550,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LANGUAGE_STANDARD = "c++11"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; @@ -529,7 +594,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LANGUAGE_STANDARD = "c++11"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; diff --git a/spec/lr/item_set_spec.cpp b/spec/lr/item_set_spec.cpp new file mode 100644 index 00000000..4c512aca --- /dev/null +++ b/spec/lr/item_set_spec.cpp @@ -0,0 +1,21 @@ +#include "spec_helper.h" + +Describe(item_sets) { + Describe(transitions) { + Grammar grammar = Grammar({ + "one", + "two" + }, { + rules::sym("one"), + rules::sym("two") + }); + + rules::rule_ptr rule = grammar.rules[string("one")]; + lr::Item item = lr::Item(string("one"), rule, 0); + + It(works) { + lr::ItemSet item_set = lr::ItemSet(item, grammar); + item_set.transitions(); + } + }; +}; diff --git a/spec/lr/parse_table_spec.cpp b/spec/lr/parse_table_spec.cpp new file mode 100644 index 00000000..e7232422 --- /dev/null +++ b/spec/lr/parse_table_spec.cpp @@ -0,0 +1,43 @@ +#include "spec_helper.h" + +Describe(parse_table_construction) { + Grammar grammar = Grammar( + { + "expression", + "term", + "factor", + "number", + "variable", + "plus", + "times", + "left_paren", + "right_paren" + }, { + rules::choice({ + rules::seq({ + rules::sym("term"), + rules::sym("plus"), + rules::sym("term") }), + rules::sym("term") }), + rules::choice({ + rules::seq({ + rules::sym("factor"), + rules::sym("times"), + rules::sym("factor") }), + rules::sym("factor") }), + rules::choice({ + rules::sym("variable"), + rules::sym("number"), + rules::seq({ + rules::sym("left_paren"), + rules::sym("expression"), + rules::sym("right_paren") }) }), + rules::pattern("\\d+"), + rules::pattern("\\w+"), + rules::str("+"), + rules::str("*"), + rules::str("("), + rules::str(")") + } + ); +}; diff --git a/spec/rules_spec.cpp b/spec/rules_spec.cpp index 6e90b056..979359ae 100644 --- a/spec/rules_spec.cpp +++ b/spec/rules_spec.cpp @@ -3,78 +3,94 @@ #include "transition_map.h" Describe(Rules) { + Describe(construction) { + rules::rule_ptr symbol1 = rules::sym("1"); + rules::rule_ptr symbol2 = rules::sym("2"); + rules::rule_ptr symbol3 = rules::sym("3"); + + It(constructs_binary_trees) { + AssertThat( + rules::seq({ symbol1, symbol2, symbol3 })->to_string(), + Equals(std::string("(seq 1 (seq 2 3))"))); + + AssertThat( + rules::choice({ symbol1, symbol2, symbol3 })->to_string(), + Equals(std::string("(choice 1 (choice 2 3))"))); + } + }; + Describe(transitions) { - rules::Symbol symbol1 = rules::Symbol(1); - rules::Symbol symbol2 = rules::Symbol(2); - rules::Symbol symbol3 = rules::Symbol(3); - rules::Symbol symbol4 = rules::Symbol(3); - + rules::rule_ptr symbol1 = rules::sym("1"); + rules::rule_ptr symbol2 = rules::sym("2"); + rules::rule_ptr symbol3 = rules::sym("3"); + rules::rule_ptr symbol4 = rules::sym("3"); + rules::rule_ptr char1 = rules::character('a'); + It(handles_symbols) { AssertThat( - symbol1.transitions(), + symbol1->transitions(), EqualsTransitionMap(TransitionMap( - { symbol1.copy() }, - { new rules::Blank() } + { symbol1 }, + { rules::blank() } ))); } - + It(handles_characters) { - rules::Char char1 = rules::Char('a'); AssertThat( - char1.transitions(), + char1->transitions(), EqualsTransitionMap(TransitionMap( - { char1.copy() }, - { new rules::Blank() } + { char1 }, + { rules::blank() } ))); } It(handles_choices) { AssertThat( - rules::Choice(symbol1, symbol2).transitions(), + rules::choice({ symbol1, symbol2 })->transitions(), EqualsTransitionMap(TransitionMap( - { symbol1.copy(), symbol2.copy() }, - { new rules::Blank(), new rules::Blank() } + { symbol1, symbol2 }, + { rules::blank(), rules::blank() } ))); } It(handles_sequences) { AssertThat( - rules::Seq(symbol1, symbol2).transitions(), + rules::seq({ symbol1, symbol2 })->transitions(), EqualsTransitionMap(TransitionMap( - { symbol1.copy() }, - { symbol2.copy() } + { symbol1 }, + { symbol2 } ))); } - + It(handles_long_sequences) { AssertThat( - rules::Seq( - rules::Seq(symbol1, symbol2), - rules::Seq(symbol3, symbol4)).transitions(), + rules::seq({ + rules::seq({ symbol1, symbol2 }), + rules::seq({ symbol3, symbol4 }) })->transitions(), EqualsTransitionMap(TransitionMap( - { symbol1.copy() }, - { new rules::Seq(symbol2, rules::Seq(symbol3, symbol4)) } + { symbol1 }, + { rules::seq({ symbol2, symbol3, symbol4 }) } ))); } It(handles_choices_with_common_starting_symbols) { AssertThat( - rules::Choice( - rules::Seq(symbol1, symbol2), - rules::Seq(symbol1, symbol3)).transitions(), + rules::choice({ + rules::seq({ symbol1, symbol2 }), + rules::seq({ symbol1, symbol3 }) })->transitions(), EqualsTransitionMap(TransitionMap( - { symbol1.copy() }, - { new rules::Choice(symbol2, symbol3) } + { symbol1 }, + { rules::choice({ symbol2, symbol3 }) } ))); } It(handles_strings) { AssertThat( - rules::String("bad").transitions(), + rules::str("bad")->transitions(), EqualsTransitionMap(TransitionMap( - { new rules::Char('b') }, - { new rules::Seq(rules::Char('a'), rules::Char('d')) } + { rules::character('b') }, + { rules::seq({ rules::character('a'), rules::character('d') }) } ))); } -}; + }; }; diff --git a/spec/spec_helper.cpp b/spec/spec_helper.cpp new file mode 100644 index 00000000..1a262dd5 --- /dev/null +++ b/spec/spec_helper.cpp @@ -0,0 +1,5 @@ +#include "spec_helper.h" + +EqualsContainerConstraint EqualsTransitionMap(const rule_tmap &expected) { + return EqualsContainer(expected, rule_tmap::elements_equal); +} diff --git a/spec/spec_helper.h b/spec/spec_helper.h new file mode 100644 index 00000000..c0005b41 --- /dev/null +++ b/spec/spec_helper.h @@ -0,0 +1,20 @@ +#ifndef TreeSitter_SpecHelper_h +#define TreeSitter_SpecHelper_h + +#include "igloo/igloo_alt.h" +#include "transition_map.h" +#include "rule.h" +#include "item.h" +#include "item_set.h" +#include "grammar.h" + +using namespace igloo; +using namespace tree_sitter; +using namespace std; + +// Assertion helpers for transition maps +typedef TransitionMap rule_tmap; +typedef bool (* rule_tmap_comparator)(const rule_tmap::pair_type &, const rule_tmap::pair_type &); +EqualsContainerConstraint EqualsTransitionMap(const rule_tmap &expected); + +#endif diff --git a/spec_helper.h b/spec_helper.h deleted file mode 100644 index a548b2b0..00000000 --- a/spec_helper.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef TreeSitter_SpecHelper_h -#define TreeSitter_SpecHelper_h - -#include "igloo/igloo_alt.h" -#include "transition_map.h" -#include "rules.h" - -using namespace igloo; -using namespace tree_sitter; - -// Assertion helpers for transition maps -namespace snowhouse { - template<> - std::string Stringize(const tree_sitter::TransitionMap &map) { - std::string result("["); - bool started = false; - for (auto pair : map) { - if (started) result += ", "; - result += (pair.first->to_string() + " => " + pair.second->to_string()); - started = true; - } - return result + "]"; - } -} - -typedef TransitionMap tmap; -typedef bool (* tmap_comparator)(const tmap::pair_type &, const tmap::pair_type &); -EqualsContainerConstraint EqualsTransitionMap(const tmap &expected) { - return EqualsContainer(expected, tmap::elements_equal); -} - -#endif diff --git a/src/grammar.cpp b/src/grammar.cpp new file mode 100644 index 00000000..2f543318 --- /dev/null +++ b/src/grammar.cpp @@ -0,0 +1,20 @@ +#include "grammar.h" + +using namespace std; + +namespace tree_sitter { + Grammar::Grammar(const rule_map &rules, const std::string &start_rule_name) : + rules(rules), + start_rule_name(start_rule_name) {}; + + Grammar::Grammar(const initializer_list &rule_names, + const initializer_list &rule_vals) { + rules = rule_map(); + auto rule_name_i = rule_names.begin(); + auto rule_i = rule_vals.begin(); + start_rule_name = *rule_name_i; + for (; rule_i != rule_vals.end(); rule_i++ && rule_name_i++) { + rules[*rule_name_i] = *rule_i; + } + } +} \ No newline at end of file diff --git a/src/grammar.h b/src/grammar.h new file mode 100644 index 00000000..fabde4e8 --- /dev/null +++ b/src/grammar.h @@ -0,0 +1,19 @@ +#ifndef __TreeSitter__grammar__ +#define __TreeSitter__grammar__ + +#include +#include "rules.h" + +namespace tree_sitter { + class Grammar { + typedef std::unordered_map rule_map; + public: + Grammar(const rule_map &rules, const std::string &start_rule_name); + Grammar(const std::initializer_list &rule_names, + const std::initializer_list &rules); + rule_map rules; + std::string start_rule_name; + }; +} + +#endif diff --git a/src/lr/item.cpp b/src/lr/item.cpp new file mode 100644 index 00000000..feafa9b4 --- /dev/null +++ b/src/lr/item.cpp @@ -0,0 +1,16 @@ +#include "item.h" + +namespace tree_sitter { + namespace lr { + Item::Item(const std::string &rule_name, rules::rule_ptr rule, int consumed_sym_count) : + rule_name(rule_name), + rule(rule), + consumed_sym_count(consumed_sym_count) {}; + + TransitionMap Item::transitions() const { + return rule->transitions().map([&](rules::rule_ptr to_rule) { + return item_ptr(new Item(rule_name, to_rule, consumed_sym_count + 1)); + }); + }; + } +} \ No newline at end of file diff --git a/src/lr/item.h b/src/lr/item.h new file mode 100644 index 00000000..157ca09e --- /dev/null +++ b/src/lr/item.h @@ -0,0 +1,24 @@ +#ifndef __TreeSitter__item__ +#define __TreeSitter__item__ + +#include +#include "rule.h" +#include "transition_map.h" + +namespace tree_sitter { + namespace lr { + class Item { + public: + Item(const std::string &rule_name, rules::rule_ptr rule, int consumed_sym_count); + TransitionMap transitions() const; + private: + std::string rule_name; + rules::rule_ptr rule; + int consumed_sym_count; + }; + + typedef std::shared_ptr item_ptr; + } +} + +#endif \ No newline at end of file diff --git a/src/lr/item_set.cpp b/src/lr/item_set.cpp new file mode 100644 index 00000000..edbf6776 --- /dev/null +++ b/src/lr/item_set.cpp @@ -0,0 +1,13 @@ +#include "item_set.h" + +namespace tree_sitter { + namespace lr { + ItemSet::ItemSet(const Item &item, const Grammar &grammar) { + + } + + TransitionMap ItemSet::transitions() const { + return TransitionMap(); + } + } +} \ No newline at end of file diff --git a/src/lr/item_set.h b/src/lr/item_set.h new file mode 100644 index 00000000..fa469cef --- /dev/null +++ b/src/lr/item_set.h @@ -0,0 +1,17 @@ +#ifndef __TreeSitter__item_set__ +#define __TreeSitter__item_set__ + +#include "item.h" +#include "grammar.h" + +namespace tree_sitter { + namespace lr { + class ItemSet { + public: + ItemSet(const Item &item, const Grammar &grammar); + TransitionMap transitions() const; + }; + } +} + +#endif diff --git a/src/rules.cpp b/src/rules.cpp new file mode 100644 index 00000000..8f2df603 --- /dev/null +++ b/src/rules.cpp @@ -0,0 +1,48 @@ +#include "rules.h" +#include "blank.h" +#include "symbol.h" +#include "choice.h" +#include "seq.h" +#include "string.h" +#include "pattern.h" +#include "char.h" + +namespace tree_sitter { + namespace rules { + rule_ptr blank() { + return rule_ptr(new Blank()); + } + + rule_ptr sym(const std::string &name) { + return rule_ptr(new Symbol(name)); + } + + rule_ptr character(char value) { + return rule_ptr(new Char(value)); + } + + rule_ptr str(const std::string &value) { + return rule_ptr(new String(value)); + } + + rule_ptr pattern(const std::string &value) { + return rule_ptr(new Pattern(value)); + } + + template + rule_ptr build_binary_tree(const std::initializer_list &rules) { + rule_ptr result(nullptr); + for (auto it = rules.end() - 1; it >= rules.begin(); --it) + result = result.get() ? rule_ptr(new RuleClass(*it, result)) : *it; + return result; + } + + rule_ptr seq(const std::initializer_list &rules) { + return build_binary_tree(rules); + } + + rule_ptr choice(const std::initializer_list &rules) { + return build_binary_tree(rules); + } + } +} \ No newline at end of file diff --git a/src/rules.h b/src/rules.h index 1651eebd..ac8feb24 100644 --- a/src/rules.h +++ b/src/rules.h @@ -2,11 +2,17 @@ #define __TreeSitter__rules__ #include "rules/rule.h" -#include "rules/blank.h" -#include "rules/char.h" -#include "rules/symbol.h" -#include "rules/choice.h" -#include "rules/seq.h" -#include "rules/string.h" + +namespace tree_sitter { + namespace rules { + rule_ptr blank(); + rule_ptr sym(const std::string &name); + rule_ptr character(char value); + rule_ptr str(const std::string &value); + rule_ptr pattern(const std::string &value); + rule_ptr seq(const std::initializer_list &rules); + rule_ptr choice(const std::initializer_list &rules); + } +} #endif diff --git a/src/rules/Pattern.cpp b/src/rules/Pattern.cpp new file mode 100644 index 00000000..cd1e52b7 --- /dev/null +++ b/src/rules/Pattern.cpp @@ -0,0 +1,21 @@ +#include "Pattern.h" +#include "transition_map.h" + +namespace tree_sitter { + namespace rules { + Pattern::Pattern(const std::string &string) : value(string) {}; + Pattern::Pattern(const char *string) : value(string) {}; + + TransitionMap Pattern::transitions() const { + return tree_sitter::TransitionMap(); + } + + bool Pattern::operator ==(tree_sitter::rules::Rule const &other) const { + return false; + } + + std::string Pattern::to_string() const { + return value; + } + } +} diff --git a/src/rules/Pattern.h b/src/rules/Pattern.h new file mode 100644 index 00000000..90c5bccd --- /dev/null +++ b/src/rules/Pattern.h @@ -0,0 +1,22 @@ +#ifndef __tree_sitter_pattern_h_ +#define __tree_sitter_pattern_h_ + +#include "rule.h" + +namespace tree_sitter { + namespace rules { + class Pattern : public Rule { + public: + Pattern(const char *string); + Pattern(const std::string &string); + TransitionMap transitions() const; + bool operator==(const Rule& other) const; + std::string to_string() const; + private: + std::string value; + }; + } +} + +#endif + diff --git a/src/rules/blank.cpp b/src/rules/blank.cpp index 7d8ec1c1..6ba3dcfd 100644 --- a/src/rules/blank.cpp +++ b/src/rules/blank.cpp @@ -13,10 +13,6 @@ namespace tree_sitter { return dynamic_cast(&rule) != NULL; } - Blank * Blank::copy() const { - return new Blank(); - } - std::string Blank::to_string() const { return "blank"; } diff --git a/src/rules/blank.h b/src/rules/blank.h index e95f9475..d1aad48f 100644 --- a/src/rules/blank.h +++ b/src/rules/blank.h @@ -9,7 +9,6 @@ namespace tree_sitter { public: Blank(); TransitionMap transitions() const; - Blank * copy() const; bool operator==(const Rule& other) const; std::string to_string() const; }; diff --git a/src/rules/char.cpp b/src/rules/char.cpp index b8fc87b5..a7e87870 100644 --- a/src/rules/char.cpp +++ b/src/rules/char.cpp @@ -1,4 +1,5 @@ #include "char.h" +#include "blank.h" #include "transition_map.h" using namespace std; @@ -6,22 +7,18 @@ using namespace std; namespace tree_sitter { namespace rules { Char::Char(char value) : value(value) {}; - + TransitionMap Char::transitions() const { - return TransitionMap({ copy() }, { new Blank() }); + return TransitionMap({ rule_ptr(new Char(value)) }, { rule_ptr(new Blank()) }); } - + bool Char::operator==(const Rule &rule) const { const Char *other = dynamic_cast(&rule); - return (other != NULL) && (other->value == value); + return (other != nullptr) && (other->value == value); } - - Char * Char::copy() const { - return new Char(value); - } - + string Char::to_string() const { return std::string("'") + &value + "'"; } } -} \ No newline at end of file +} diff --git a/src/rules/char.h b/src/rules/char.h index 42c8267c..9c83ac8c 100644 --- a/src/rules/char.h +++ b/src/rules/char.h @@ -9,13 +9,12 @@ namespace tree_sitter { public: Char(char value); TransitionMap transitions() const; - Char * copy() const; bool operator==(const Rule& other) const; std::string to_string() const; private: char value; - }; + }; } } -#endif \ No newline at end of file +#endif diff --git a/src/rules/choice.cpp b/src/rules/choice.cpp index fdd33352..4af430b6 100644 --- a/src/rules/choice.cpp +++ b/src/rules/choice.cpp @@ -3,7 +3,6 @@ namespace tree_sitter { namespace rules { - Choice::Choice(const Rule &left, const Rule &right) : left(left.copy()), right(right.copy()) {}; Choice::Choice(rule_ptr left, rule_ptr right) : left(left), right(right) {}; TransitionMap Choice::transitions() const { @@ -19,10 +18,6 @@ namespace tree_sitter { return (other != NULL) && (*other->left == *left) && (*other->right == *right); } - Choice * Choice::copy() const { - return new Choice(left, right); - } - std::string Choice::to_string() const { return std::string("(choice ") + left->to_string() + " " + right->to_string() + ")"; } diff --git a/src/rules/choice.h b/src/rules/choice.h index 823fb308..e69ed716 100644 --- a/src/rules/choice.h +++ b/src/rules/choice.h @@ -3,14 +3,12 @@ #include "rule.h" -namespace tree_sitter { +namespace tree_sitter { namespace rules { class Choice : public Rule { public: - Choice(const Rule &left, const Rule &right); - Choice(std::shared_ptr left, std::shared_ptr right); + Choice(rule_ptr left, rule_ptr right); TransitionMap transitions() const; - Choice * copy() const; bool operator==(const Rule& other) const; std::string to_string() const; private: diff --git a/src/rules/rule.cpp b/src/rules/rule.cpp new file mode 100644 index 00000000..629dc804 --- /dev/null +++ b/src/rules/rule.cpp @@ -0,0 +1,7 @@ +#include "rule.h" + +std::ostream& operator<<(std::ostream& stream, const tree_sitter::rules::Rule &rule) +{ + stream << rule.to_string(); + return stream; +} diff --git a/src/rules/rule.h b/src/rules/rule.h index 3f6152e9..2e4ee5e8 100644 --- a/src/rules/rule.h +++ b/src/rules/rule.h @@ -10,7 +10,6 @@ namespace tree_sitter { class Rule { public: virtual TransitionMap transitions() const = 0; - virtual Rule * copy() const = 0; virtual bool operator==(const Rule& other) const = 0; virtual std::string to_string() const = 0; }; @@ -19,4 +18,6 @@ namespace tree_sitter { } } +std::ostream& operator<<(std::ostream& stream, const tree_sitter::rules::Rule &rule); + #endif \ No newline at end of file diff --git a/src/rules/seq.cpp b/src/rules/seq.cpp index df865611..2285c3d4 100644 --- a/src/rules/seq.cpp +++ b/src/rules/seq.cpp @@ -2,13 +2,12 @@ #include "blank.h" #include "transition_map.h" -namespace tree_sitter { +namespace tree_sitter { namespace rules { - Seq::Seq(const Rule &left, const Rule &right) : left(left.copy()), right(right.copy()) {}; Seq::Seq(rule_ptr left, rule_ptr right) : left(left), right(right) {}; - + TransitionMap Seq::transitions() const { - return left->transitions().map([&](rule_ptr left_rule) -> rule_ptr { + return left->transitions().map([&](rule_ptr left_rule) -> rule_ptr { if (typeid(*left_rule) == typeid(Blank)) return right; else @@ -21,12 +20,8 @@ namespace tree_sitter { return (other != NULL) && (*other->left == *left) && (*other->right == *right); } - Seq * Seq::copy() const { - return new Seq(left, right); - } - std::string Seq::to_string() const { return std::string("(seq ") + left->to_string() + " " + right->to_string() + ")"; } } -} \ No newline at end of file +} diff --git a/src/rules/seq.h b/src/rules/seq.h index fcc8b57f..bafbad2d 100644 --- a/src/rules/seq.h +++ b/src/rules/seq.h @@ -7,10 +7,8 @@ namespace tree_sitter { namespace rules { class Seq : public Rule { public: - Seq(const Rule &left, const Rule &right); - Seq(std::shared_ptr left, std::shared_ptr right); + Seq(rule_ptr left, rule_ptr right); TransitionMap transitions() const; - Seq * copy() const; bool operator==(const Rule& other) const; std::string to_string() const; private: @@ -20,4 +18,4 @@ namespace tree_sitter { } } -#endif \ No newline at end of file +#endif diff --git a/src/rules/string.cpp b/src/rules/string.cpp index a24d80c3..80157b21 100644 --- a/src/rules/string.cpp +++ b/src/rules/string.cpp @@ -8,10 +8,9 @@ namespace tree_sitter { String::String(std::string value) : value(value) {}; TransitionMap String::transitions() const { - rule_ptr result = rule_ptr(new Char(value[0])); - for (int i = 1; i < value.length(); i++) { + auto result = rule_ptr(new Char(value[0])); + for (int i = 1; i < value.length(); i++) result = rule_ptr(new Seq(result, rule_ptr(new Char(value[i])))); - } return result->transitions(); } diff --git a/src/rules/string.h b/src/rules/string.h index 585f24f1..0e1f4b4b 100644 --- a/src/rules/string.h +++ b/src/rules/string.h @@ -18,4 +18,4 @@ namespace tree_sitter { } } -#endif \ No newline at end of file +#endif diff --git a/src/rules/symbol.cpp b/src/rules/symbol.cpp index 167b99d7..d3b83fae 100644 --- a/src/rules/symbol.cpp +++ b/src/rules/symbol.cpp @@ -1,25 +1,23 @@ #include "symbol.h" +#include "blank.h" #include "transition_map.h" namespace tree_sitter { namespace rules { - Symbol::Symbol(int id) : id(id) {}; + Symbol::Symbol(const std::string &name) : name(name) {}; + Symbol::Symbol(const char *name) : name(name) {}; TransitionMap Symbol::transitions() const { - return TransitionMap({ copy() }, { new Blank() }); + return TransitionMap({ rule_ptr(new Symbol(name)) }, { rule_ptr(new Blank()) }); } bool Symbol::operator==(const Rule &rule) const { const Symbol *other = dynamic_cast(&rule); - return (other != NULL) && (other->id == id); - } - - Symbol * Symbol::copy() const { - return new Symbol(id); + return (other != NULL) && (other->name == name); } std::string Symbol::to_string() const { - return std::to_string(id); - } + return name; + } } } \ No newline at end of file diff --git a/src/rules/symbol.h b/src/rules/symbol.h index 40ebe862..d767e39f 100644 --- a/src/rules/symbol.h +++ b/src/rules/symbol.h @@ -7,13 +7,14 @@ namespace tree_sitter { namespace rules { class Symbol : public Rule { public: - Symbol(int id); + Symbol(const std::string &name); + Symbol(const char *name); TransitionMap transitions() const; Symbol * copy() const; bool operator==(const Rule& other) const; std::string to_string() const; private: - int id; + std::string name; }; } } diff --git a/src/transition_map.h b/src/transition_map.h index 7ba4f876..1b3badd0 100644 --- a/src/transition_map.h +++ b/src/transition_map.h @@ -3,6 +3,7 @@ #include #include +#include #include "rules.h" namespace tree_sitter { @@ -13,14 +14,14 @@ namespace tree_sitter { typedef std::shared_ptr mapped_ptr; typedef std::pair pair_type; typedef std::vector contents_type; - + 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 keys, std::initializer_list values) : TransitionMap() { + TransitionMap(std::initializer_list keys, std::initializer_list values) : TransitionMap() { auto value_iter(values.begin()); for (auto key_iter(keys.begin()); key_iter != keys.end(); ++key_iter) { add(*key_iter, *value_iter); @@ -36,23 +37,15 @@ namespace tree_sitter { const_iterator begin() const { return contents.begin(); } const_iterator end() const { return contents.end(); } - void add(const rules::Rule *on_rule, const MappedType *to_value) { - rule_ptr key(on_rule); - mapped_ptr value(to_value); - contents.push_back(pair_type(key, value)); - } - - void add(rule_ptr on_rule, mapped_ptr to_value) { - rule_ptr key(on_rule); - mapped_ptr value(to_value); - contents.push_back(pair_type(key, value)); + void add(const rule_ptr on_rule, const mapped_ptr to_value) { + contents.push_back(pair_type(on_rule, to_value)); } size_t size() const { return contents.size(); } - mapped_ptr operator[](rules::Rule const &on_rule) const { + mapped_ptr operator[](rules::Rule const &on_rule) { pair_type *pair = pair_for_key(on_rule); if (pair) return pair->second; @@ -73,8 +66,9 @@ namespace tree_sitter { } } - TransitionMap map(std::function map_fn) { - TransitionMap result; + template + TransitionMap map(std::function(mapped_ptr)> map_fn) { + TransitionMap result; for (pair_type pair : *this) result.add(pair.first, map_fn(pair.second)); return result; @@ -91,6 +85,20 @@ namespace tree_sitter { contents_type contents; }; + + template + std::ostream& operator<<(std::ostream &stream, const TransitionMap &map) { + stream << std::string("["); + bool started = false; + for (auto pair : map) { + if (started) stream << std::string(", "); + stream << (pair.first->to_string() + " => " + pair.second->to_string()); + started = true; + } + stream << std::string("]"); + return stream; + } } -#endif \ No newline at end of file + +#endif