OSDN Git Service

マージ。
[simplecms/utakata.git] / parser.cpp
index f45b022..f639079 100755 (executable)
@@ -3,36 +3,42 @@
 
 #include "parser.h"
 #include "lexeme.h"
+#include "lexeme_data.h"
 #include "lexer.h"
 #include "lexeme_id.h"
-#include "tree.h"
-#include "literal.h"
 #include "datum_id.h"
+#include "reader.h"
+#include "object.h"
+#include "gc.h"
+#include "primitive.h"
+#include "primitive_class.h"
+#include "primitive_util.h"
+#include "data_castor.h"
 
 using namespace utakata;
-using namespace utakata::interpreter;
 using namespace utakata::parser;
 using namespace utakata::lexeme;
+using namespace utakata::interpreter;
 
-parser::DatumException::DatumException (std::string str) : str_()
+parser::DatumException::DatumException(std::string str) : str_()
 {
     // エラーメッセージを定義する。
     std::stringstream ss;
     ss << "datum error ! -- message : [" << str << "]" << std::endl;
-    str_ = ss.str ();
+    str_ = ss.str();
 }
 
-const char* parser::DatumException::what () const throw ()
+const char* parser::DatumException::what() const throw()
 {
-    return str_.c_str ();
+    return str_.c_str();
 }
 
 ////////////////////////////
 // Parser Implementations //
-////////////////////////////
+///////////////////////////
 
-parser::Parser::Parser (smart_ptr<lexer::Lexer> l) : lexer_(l),
-                                                     handler_()
+parser::Parser::Parser(smart_ptr<lexer::Lexer> l) : lexer_(l),
+                                                    handler_()
 {
     // 初期状態用ハンドラの設定
     std::pair<PARSERSTATUS, smart_ptr<IParserHandler> > p;
@@ -41,54 +47,69 @@ parser::Parser::Parser (smart_ptr<lexer::Lexer> l) : lexer_(l),
     handler_.insert(p);
 
     // リスト内部用ハンドラの設定
-    p.first = PS_LIST_CAR;
+    p.first = PS_LIST;
     p.second.add(new ListHandler);
     handler_.insert(p);
 
     // .内用ハンドラの設定
-    p.first = PS_AFTER_DOT;
-    p.second.add(new DotHandler);
+    p.first = PS_END_DOT;
+    p.second.add(new DotEndHandler);
     handler_.insert(p);
 
-    // abbreviation用ハンドラの設定
+    // abbreviation 用ハンドラの設定
     p.first = PS_ABBREVIATION;
     p.second.add(new AbbrevHandler);
     handler_.insert(p);
+
+    // error 用のハンドラの設定
+    p.first = PS_ERROR;
+    p.second.add(new ErrorHandler);
+    handler_.insert(p);
 }
 
-smart_ptr<syntax::Tree> parser::Parser::parse (smart_ptr<utf8::UTF8InputStream>& strm)
+smart_ptr<data::Object> parser::Parser::parse(smart_ptr<reader::StreamReader>& strm,
+                                              gc::GarbageCollector& gc)
 {
-    std::stack<PARSERSTATUS> statusstack; statusstack.push(PS_INIT);
-    smart_ptr<lexeme::ILexeme> lexm;
-    smart_ptr<syntax::Tree> root(new syntax::Tree());
-    syntax::Tree::iterator it = root->begin();
-    std::stack<syntax::Tree::iterator> stack;
-    stack.push(it);
-    
-    while (! (lexm = lexer_->lex (strm)).isNull ()) {
-        if (lexm->getID() == lexeme::LexemeID::eos)
-        {
-            break;
-        }
+    HandlerData data(gc);
+    data.status.push(PS_INIT);
 
-        // 基本的にすべてハンドラに任せる。
-        handler_[statusstack.top()]->exec(root, lexm, stack, statusstack);
-    }
+    while(!data.status.empty()) {
 
-    // 終端に逹した時点で、stackにデータが殘っていたら例外。
-    
-    if (!stack.empty())
-    {
-        throw DatumException ("()の整合性が取れていません");
+        if(data.status.top() != PS_ERROR)
+        {
+            if (data.chain)
+            {
+                data.chain = false;
+            }
+            else
+            {
+                data.lexm = lexer_->lex(strm);
+            }
+            
+            if(data.lexm.isNull() ||
+               data.lexm->getID() == lexeme::LexemeID::eos)
+            {
+                break;
+            }
+            // 基本的にすべてハンドラに任せる。
+            handler_[data.status.top()]->exec(data);
+        }
+        else
+        {
+            // ERROR だったら、強制的にハンドラを回してループから抜ける。
+            handler_[data.status.top()]->exec(data);
+        }
     }
 
-    return root;
+    // stackのtopにはmainが殘ったままなので、data.stackのtopを追加してやる。
+    smart_ptr<data::Object> ret(new data::Object(data.stack.top()));
+    return ret;
 }
 
-bool parser::isAbbrev (smart_ptr<lexeme::ILexeme> l)
+bool parser::isAbbrev(smart_ptr<lexeme::ILexeme> l)
 {
     // abbreviation かどうかを判別する。
-    switch (l->getID ().toEnum ())
+    switch(l->getID().toEnum())
     {
     case lexeme::LexemeID::BACKQUOTE:        return true;
     case lexeme::LexemeID::QUOTE:            return true;
@@ -103,190 +124,347 @@ bool parser::isAbbrev (smart_ptr<lexeme::ILexeme> l)
     }
 }
 
+interpreter::IObject* parser::makePrimitiveFromLexeme(smart_ptr<lexeme::ILexeme> l)
+{
+    // 各lexemeに対応した固定lexemeを返す。
+    interpreter::IObject* o = NULL;
+    switch (l->getID().toEnum())
+    {
+    case lexeme::LexemeID::STRING:
+        return util::makeString(l->getData()->string->str);
+    case lexeme::LexemeID::CHARACTOR:
+        return util::makeCharactor(l->getData()->charactor->spec);
+    case lexeme::LexemeID::IDENTIFIER:
+        return util::makeSymbol(l->getData()->symbol->id);
+    case lexeme::LexemeID::BOOLEAN:
+        return util::makeBoolean(l->getData()->boolean->boolean);
+    case lexeme::LexemeID::NUMBER:
+    {
+        lexeme::NumberData& t = *(l->getData()->number);
+        return util::makeNumber(t.real, t.imagin, t.exact,
+                                t.radix);
+    }
+    case lexeme::LexemeID::BACKQUOTE:
+        return util::Abbrev<primitive::Quasiquote>::make();
+    case lexeme::LexemeID::QUOTE:
+        return util::Abbrev<primitive::Quote>::make();
+    case lexeme::LexemeID::UNQUOTE:
+        return util::Abbrev<primitive::Unquote>::make();
+    case lexeme::LexemeID::UNQUOTESPLICING:
+        return util::Abbrev<primitive::UnquoteSplicing>::make();
+    case lexeme::LexemeID::SYNTAX:
+        return util::Abbrev<primitive::Syntax>::make();
+    case lexeme::LexemeID::QUASISYNTAX:
+        return util::Abbrev<primitive::Quasisyntax>::make();
+    case lexeme::LexemeID::UNSYNTAX:
+        return util::Abbrev<primitive::Unsyntax>::make();
+    case lexeme::LexemeID::UNSYNTAXSPLICING:
+        return util::Abbrev<primitive::UnsyntaxSplicing>::make();
+    default:
+        break;
+    }
+
+    return o;
+}
+
+/////////////////////
+// parser handlers //
+/////////////////////
 
-bool InitHandler::exec_(smart_ptr<syntax::Tree>& main,
-                        const smart_ptr<lexeme::ILexeme>& lexm,
-                        treestack& stack,
-                        std::stack<PARSERSTATUS>& status)
+bool InitHandler::exec_(HandlerData& data)
 {
+    data.status.pop();
     // 初期状態の解釈処理を行う。
-    if (lexm->getID () == lexeme::LexemeID::openParenthesis)
+    if(data.lexm->getID() == lexeme::LexemeID::openParenthesis)
     {
-        // 開き括弧である場合、もはやmainをツリーに登録する必要も無く、
-        // iteratorをstackするだけでよい。stackしたiteratorは、原則として
-        // )が来ないと取り外せない。
-        stack.push(syntax::Tree::iterator());
+        // 開き括弧である場合、compoundsに新しくpushして返る。
+        data.compounds.push(std::vector<data::Object>());
+        data.status.push(PS_LIST);
     }
-    else if (lexm->getID () == lexeme::LexemeID::string ||
-             lexm->getID () == lexeme::LexemeID::number ||
-             lexm->getID () == lexeme::LexemeID::identifier ||
-             lexm->getID () == lexeme::LexemeID::charactor ||
-             lexm->getID () == lexeme::LexemeID::boolean)
+    else if(data.lexm->getID() == lexeme::LexemeID::string ||
+            data.lexm->getID() == lexeme::LexemeID::number ||
+            data.lexm->getID() == lexeme::LexemeID::identifier ||
+            data.lexm->getID() == lexeme::LexemeID::charactor ||
+            data.lexm->getID() == lexeme::LexemeID::boolean)
     {
-        // それぞれの場合、 lexeme_datum として扱われる。
-        // stack.topのiteratorにconsする。
-        main->cons(stack.top(), syntax::makeLexemeDatum(
-                       literal::generateLiteral(lexm)));
-        // statusをpopする。
-        status.pop();
+        // それぞれの場合、単純にstackに各オブジェクトをpushする。
+
+        data::Object o = data::Object(false,
+                                      data.gc.add(makePrimitiveFromLexeme(data.lexm)));
+        if (data.compounds.empty())
+        {
+            data.stack.push(o);
+        }
+        else
+        {
+            data.compounds.top().push_back(o);
+        }
     }
-    else if (isAbbrev(lexm))
+    else if(isAbbrev(data.lexm))
     {
-        // abbreviaitionである場合でも、これはまったくの同様
-        // である。ただし、abbreviationは正確にはconpound datumを構成
-        // するため、新規イテレータを導入する必要がある。
-        syntax::Tree::iterator it2;
-        main->cons(it2, syntax::makeAbbreviation(
-                       literal::generateLiteral(lexm)));
-        stack.push(it2);
-
-        // status stackに、PS_ABBREVIATIONとPS_INITを積む。
-        status.push(PS_ABBREVIATION);
-        status.push(PS_INIT);
+        // abbreviation である場合には、 全体をリストに展開するため、carまでは
+        // 設定された状態にする。
+        std::vector<data::Object> v;
+        v.push_back(data::Object(false,
+                                 data.gc.add(makePrimitiveFromLexeme(data.lexm))));
+
+        data.compounds.push(v);
+
+        // status stack に、 PS_ABBREVIATIONとPS_INITを積む。
+        data.status.push(PS_ABBREVIATION);
+        data.status.push(PS_INIT);
     }
     else
     {
-        throw DatumException ("datum の開始記号ではありません");
+        throw DatumException("datum の開始記号ではありません");
     }
 
     return true;
 }
 
-// List内部処理のハンドリング
+// List 内部処理のハンドリング
 
-bool ListHandler::exec_(smart_ptr<syntax::Tree>& main,
-                        const smart_ptr<lexeme::ILexeme>& lexm,
-                        treestack& stack,
-                        std::stack<PARSERSTATUS>& status)
+bool ListHandler::exec_(HandlerData& data)
 {
-    // listの内部である場合。
-    if (lexm->getID () == lexeme::LexemeID::openParenthesis)
+    // list の開始部分である場合。
+    if(data.lexm->getID() == lexeme::LexemeID::openParenthesis)
     {
-        // スタックに積む。
-        stack.push(main);
-        main.add(new syntax::Tree);
-        // 再度積む。
-        status.push(PS_LIST_CAR);
+        // 更にcompoundsに追加して積む。
+        data.compounds.push(std::vector<data::Object>());
+        data.status.push(PS_LIST);
     }
-    else if (lexm->getID () == lexeme::LexemeID::closeParenthesis)
+    else if(data.lexm->getID() == lexeme::LexemeID::closeParenthesis)
     {
-        // スタックから取り出す。
-        smart_ptr<syntax::Tree> tree2 = stack.top(); stack.pop();
-        // carが空かどうかでチェックする。
-        if (!syntax::hasCar(*tree2))
+        // 原則として、閉括弧が来た時点で終了とするだけでよい。
+        // 現在のtopにあるcompoundsが、データであるとされているため、
+        // とりあえずtopにあるvectorをConsの繋がりに変換する。
+
+        std::vector<data::Object> v = data.compounds.top(); data.compounds.pop();
+        // vectorをConsへと変換するには、次のようにして後ろからやっていく
+        // 方式が一番面倒がない。
+        // 1. cdrをnil、carをvectorの末尾であるデータとしたconsを作成する。
+        // 2. vectorの次のデータをcar、前のconsをcdrとしたconsを作成する。
+        // 3. 先頭まで続ける。
+
+        if (v.size() == 0)
         {
-            tree2->appendTreeToCar(main);
+            // サイズが0の場合には、nilを設定する。
+            data::Object o = data::Object(false,
+                                          data.gc.add(util::makeNil()));
+            pushList(data, o);
         }
         else
         {
-            tree2->concat(main);
+            // 後ろから前に向かっていく。
+            std::vector<data::Object>::reverse_iterator begin = v.rbegin(),
+                end = v.rend();
+            // ちょっと面倒すぎるなこれ。
+            data::Object o = data::Object(
+                false, data.gc.add(
+                    util::makeCons(*begin,
+                                   data::Object(false, data.gc.add(util::makeNil()))))
+                );
+            ++begin;
+            for (; begin != end; ++begin)
+            {
+                // 順次oに再設定していく。
+                o = data::Object(
+                    false, data.gc.add(
+                        util::makeCons(*begin, o)));
+            }
+            pushList(data, o);
         }
-        main = tree2;
-        // 現在のPS_LIST_CARをpopする。
-        status.pop();
+
+        data.status.pop();
     }
-    else if (lexm->getID () == lexeme::LexemeID::string ||
-             lexm->getID () == lexeme::LexemeID::number ||
-             lexm->getID () == lexeme::LexemeID::identifier ||
-             lexm->getID () == lexeme::LexemeID::charactor ||
-             lexm->getID () == lexeme::LexemeID::boolean)
+    else if (data.lexm->getID() == lexeme::LexemeID::string ||
+             data.lexm->getID() == lexeme::LexemeID::number ||
+             data.lexm->getID() == lexeme::LexemeID::identifier ||
+             data.lexm->getID() == lexeme::LexemeID::charactor ||
+             data.lexm->getID() == lexeme::LexemeID::boolean)
     {
-        // carが空かどうかをチェックして、設定を行う必要がある。
-        if (!syntax::hasCar(*main))
+        // データスタックの頂上にあるvectorに追加する。
+        data.compounds.top().push_back(
+            data::Object(
+                false, data.gc.add(makePrimitiveFromLexeme(data.lexm))));
+    }
+    else if(isAbbrev(data.lexm))
+    {
+        // abbreviation は、結論としてはリストに展開される。carは常にabbreviationである
+        // とすることで問題は無いので、作成したconsを、topに置くことで実現する。
+
+        std::vector<data::Object> v;
+        v.push_back(data::Object(false,
+                                 data.gc.add(makePrimitiveFromLexeme(data.lexm))));
+
+        data.compounds.push(v);
+
+        // status stack に、 PS_ABBREVIATION と PS_INIT を積む。
+        data.status.push(PS_ABBREVIATION);
+        data.status.push(PS_INIT);
+    }
+    else if(data.lexm->getID() == lexeme::LexemeID::dot)
+    {
+        // .が来た場合で、topのvectorがemptyだったらどうしようもなくなるので終了。
+        
+        if (data.compounds.top().empty())
         {
-            syntax::setLiteralToCar(*main, literal::generateLiteral(lexm));
+            data.status.push(PS_ERROR);
+            data.error = "necessary one datum previous dot";
         }
         else
         {
-            main->concat(literal::generateLiteral(lexm));
+            // この時点で、終わり方が確定したため、別のハンドラに任せる。
+            // ただし、compoundの方は特に変化は必要が無いので、そちらはそのまま。
+            data.status.pop();
+            data.status.push(PS_END_DOT);
+            data.status.push(PS_INIT);
         }
     }
-    else if (isAbbrev(lexm))
+    else
+    {
+        // 上記以外は許容しない。
+        data.status.push(PS_ERROR);
+    }
+
+    return true;
+}
+
+void ListHandler::pushList(HandlerData& data, data::Object& o)
+{
+    if (!data.compounds.empty())
+    {
+        data.compounds.top().push_back(o);
+    }
+    else
     {
-        // abbreviation を判別して status を返す。
-        // この場合、新規にツリーを作成して、再度設定を行う。
-        stack.push(main);
-        main.add(new syntax::Tree);
-        syntax::setLiteralToCar(*main, literal::generateLiteral(lexm),
-                                getAbbrevID(lexm));
-        // status stackに、PS_PABBREVIATIONとPS_INITを積む。
-        status.push(PS_ABBREVIATION);
-        status.push(PS_INIT);
+        data.stack.push(o);
     }
-    else if (lexm->getID() == lexeme::LexemeID::dot)
+}
+
+bool DotEndHandler::exec_(HandlerData& data)
+{
+    // .後の) を待つ部分のハンドラ。
+    // このハンドラでは、) 以外が来た場合にはすべて構文エラーとなる。
+    data.status.pop();
+    if(data.lexm->getID() == lexeme::LexemeID::closeParenthesis)
     {
-        // .が来た場合、かつcarが設定されていない場合には、エラーとなる。
-        if (!syntax::hasCar(*main))
+        // stackの頂点とcompoundsのトップを取得する。
+<<<<<<< HEAD
+=======
+        data::Object t = data.stack.top(); data.stack.pop();
+>>>>>>> 6403bdd4479dc5a3e6ca42aa2dc9b0dc4d6bf71d
+        std::vector<data::Object> v = data.compounds.top(); data.compounds.pop();
+        // vectorをConsへと変換するには、次のようにして後ろからやっていく
+        // 方式が一番面倒がない。
+        // 1. cdrをstackのtop、carをvectorの末尾であるデータとしたconsを作成する。
+        // 2. vectorの次のデータをcar、前のconsをcdrとしたconsを作成する。
+        // 3. 先頭まで続ける。
+
+<<<<<<< HEAD
+=======
+        // 
+>>>>>>> 6403bdd4479dc5a3e6ca42aa2dc9b0dc4d6bf71d
         {
-            throw DatumException ("リストの先頭に . が設定されることは出来ません");
+            // 後ろから前に向かっていく。
+            std::vector<data::Object>::reverse_iterator begin = v.rbegin(),
+                end = v.rend();
+            // ちょっと面倒すぎるなこれ。
+<<<<<<< HEAD
+            // cdrにcompoundsの末尾を、carにその前を設定する。
+            data::Object o = data::Object(
+                false, data.gc.add(
+                        util::makeCons(begin[1], begin[0]))
+                );
+            begin += 2;
+=======
+            data::Object o = data::Object(
+                false, data.gc.add(
+                    util::makeCons(*begin, o))
+                );
+            ++begin;
+>>>>>>> 6403bdd4479dc5a3e6ca42aa2dc9b0dc4d6bf71d
+            for (; begin != end; ++begin)
+            {
+                // 順次oに再設定していく。
+                o = data::Object(
+                    false, data.gc.add(
+                        util::makeCons(*begin, o)));
+            }
+
+            if (!data.compounds.empty())
+            {
+                data.compounds.top().push_back(o);
+            }
+            else
+            {
+                data.stack.push(o);
+            }
         }
-        status.push(PS_AFTER_DOT);
+
+        // ここまでは、すべてDataSpace内部のDataEntityを対象に処理しているため、
+        // Objectで正しく受け渡しができていれば問題は発生しない。
+    }
+    else
+    {
+        // 上記以外は許容しない。
+        data.status.push(PS_ERROR);
     }
 
     return true;
 }
 
-// dot処理内部のハンドリング
+// Abbreviation 処理のハンドリング。
 
-bool DotHandler::exec_(smart_ptr<syntax::Tree>& main,
-                       const smart_ptr<lexeme::ILexeme>& lexm,
-                       treestack& stack,
-                       std::stack<PARSERSTATUS>& status)
+bool AbbrevHandler::exec_(HandlerData& data)
 {
-    // .の後である場合。
-    if (lexm->getID () == lexeme::LexemeID::openParenthesis)
-    {
-        // 開き括弧である場合
-        stack.push(main);
-        main.add(new syntax::Tree);
-        status.push(PS_LIST_CAR);
-    }
-    else if (lexm->getID () == lexeme::LexemeID::string ||
-             lexm->getID () == lexeme::LexemeID::number ||
-             lexm->getID () == lexeme::LexemeID::identifier ||
-             lexm->getID () == lexeme::LexemeID::charactor ||
-             lexm->getID () == lexeme::LexemeID::boolean)
+    // abbreviationの場合、すでにPS_INITを事前に積んであるため、
+    // 一つ分のdatumが来ていることが確定している。
+    // すでにabbreviation分のObjectはcompoundのtopに積んであるため、
+    // consを作成して、compoundかstackのtopに積むだけ。
+
+    std::vector<data::Object> v = data.compounds.top(); data.compounds.pop();
+
+    if (v.size() != 2)
     {
-        // リテラルの場合、単純に戻るのみとなる。
-        main->appendCdr(syntax::DatumID::literal);
-        main->cdr()->setLiteral(literal::generateLiteral(lexm));
-        status.pop();
+        data.status.push(PS_ERROR);
     }
-    else if (lexm->getID() == lexeme::LexemeID::closeParenthesis)
+    else
     {
-        smart_ptr<syntax::Tree> tree2 = stack.top(); stack.pop();
-        // carが空かどうかでチェックする。
-        if (!syntax::hasCar(*tree2))
+        // まだcompoundsが存在している場合には、これを返すようにする。
+        data::Object c = data::Object(
+            false, data.gc.add(util::makeCons(
+                                   v[1],
+                                   data::Object(false, data.gc.add(util::makeNil()))
+                                   )));
+        data::Object o =
+            data::Object(false,
+                         data.gc.add(util::makeCons(v[0], c)));
+        if (!data.compounds.empty())
         {
-            tree2->appendTreeToCar(main);
+            data.compounds.top().push_back(o);
         }
         else
         {
-            tree2->concat(main);
+            data.stack.push(o);
         }
-        main = main->cdr();
-        // 基本的にステータスはpopするのみ。
-        status.pop();
     }
+
+    data.status.pop();
+    data.chain = true;
+
     return true;
 }
 
-// ABBREVIATION処理のハンドリング。
+// syntax error のハンドリング
 
-bool AbbrevHandler::exec_(smart_ptr<syntax::Tree>& main,
-                          const smart_ptr<lexeme::ILexeme>& lexm,
-                          treestack& stack,
-                          std::stack<PARSERSTATUS>& status)
+bool ErrorHandler::exec_(HandlerData& data)
 {
-    // この場合には、stackのtopに現在のツリーをconcatし、その後
-    // 更にpopして追加を行う。
-    // carが空かどうかをチェックして、設定を行う必要がある。
-    smart_ptr<syntax::Tree> t2 = stack.top(); stack.pop();
-    t2->concat(main);
-
-    // この時点で、abbrev開始前のnodeに戻ることができる。
-    main = t2;
-    status.pop();
+    // 基本的にはエラーのハンドリングを行うだけ。
+    // 一応発生した前後の位置と発生した lexeme くらいは表示したいかな。
+    std::stringstream ss;
+    ss << "syntax error:" << data.error;
+    throw DatumException(ss.str());
 
     return true;
 }