diff --git a/coco/Parser.cpp b/coco/Parser.cpp deleted file mode 100644 index 9fe0289..0000000 --- a/coco/Parser.cpp +++ /dev/null @@ -1,859 +0,0 @@ -/*---------------------------------------------------------------------- -Compiler Generator Coco/R, -Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz -extended by M. Loeberbauer & A. Woess, Univ. of Linz -ported to C++ by Csaba Balazs, University of Szeged -with improvements by Pat Terry, Rhodes University - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -As an exception, it is allowed to write an extension of Coco/R that is -used as a plugin in non-free software. - -If not otherwise stated, any source code generated by Coco/R (other than -Coco/R itself) does not fall under the GNU General Public License. ------------------------------------------------------------------------*/ - - -#include -#include "Parser.h" -#include "Scanner.h" - - - - -void Parser::SynErr(int n) { - if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n); - errDist = 0; -} - -void Parser::SemErr(const wchar_t* msg) { - if (errDist >= minErrDist) errors->Error(t->line, t->col, msg); - errDist = 0; -} - -void Parser::Get() { - for (;;) { - t = la; - la = scanner->Scan(); - if (la->kind <= maxT) { ++errDist; break; } - - if (dummyToken != t) { - dummyToken->kind = t->kind; - dummyToken->pos = t->pos; - dummyToken->col = t->col; - dummyToken->line = t->line; - dummyToken->next = NULL; - coco_string_delete(dummyToken->val); - dummyToken->val = coco_string_create(t->val); - t = dummyToken; - } - la = t; - } -} - -void Parser::Expect(int n) { - if (la->kind==n) Get(); else { SynErr(n); } -} - -void Parser::ExpectWeak(int n, int follow) { - if (la->kind == n) Get(); - else { - SynErr(n); - while (!StartOf(follow)) Get(); - } -} - -bool Parser::WeakSeparator(int n, int syFol, int repFol) { - if (la->kind == n) {Get(); return true;} - else if (StartOf(repFol)) {return false;} - else { - SynErr(n); - while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) { - Get(); - } - return StartOf(syFol); - } -} - -void Parser::Xreate() { - while (StartOf(1)) { - if (la->kind == _ident) { - FDecl(); - } else if (la->kind == 37 /* "rule" */) { - RuleDecl(); - } else if (la->kind == 29 /* "pass" */) { - PassData(); - } else { - Imprt(); - } - } -} - -void Parser::FDecl() { - std::wstring fname; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; - Ident(fname); - Expect(_assign); - Expect(11 /* "function" */); - Expect(12 /* ":" */); - Function* f = new Function(fname); CodeScope* entry = f->getEntryScope(); - if (StartOf(2)) { - Type(typOut); - f->setReturnType(typOut); - } else if (la->kind == _lparen) { - Get(); - if (la->kind == _ident) { - Ident(varname); - Expect(12 /* ":" */); - Type(typIn); - f->addArg(std::move(varname), move(typIn)); - while (la->kind == 13 /* "," */) { - Get(); - Ident(varname); - Expect(12 /* ":" */); - Type(typIn); - f->addArg(std::move(varname), move(typIn)); - } - } - Expect(_rparen); - Expect(_implic); - Type(typOut); - f->setReturnType(typOut); - while (la->kind == 13 /* "," */) { - Get(); - FnTag(f); - } - } else SynErr(49); - BDecl(entry); - root.add(f); -} - -void Parser::RuleDecl() { - Expect(37 /* "rule" */); - Expect(12 /* ":" */); - RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; - Expect(_lparen); - Ident(arg); - Expect(12 /* ":" */); - Domain(typ); - args.add(arg, typ); - while (la->kind == 13 /* "," */) { - Get(); - Ident(arg); - Expect(12 /* ":" */); - Domain(typ); - args.add(arg, typ); - } - Expect(_rparen); - if (la->kind == 38 /* "case" */) { - Get(); - RGuard(guards); - while (la->kind == 13 /* "," */) { - Get(); - RGuard(guards); - } - } - Expect(19 /* "{" */); - RBody(args, guards); - Expect(21 /* "}" */); -} - -void Parser::PassData() { - Expect(29 /* "pass" */); - Expect(_lparen); - Expect(_ident); - Expect(_rparen); - Expect(19 /* "{" */); - while (la->kind == 30 /* "operator" */) { - InDecl(); - } - Expect(21 /* "}" */); -} - -void Parser::Imprt() { - Expect(27 /* "import" */); - Expect(28 /* "raw" */); - Expect(_lparen); - Expect(_string); - root.__rawImports.push_back(Atom(t->val).get()); - Expect(_rparen); - Expect(20 /* ";" */); -} - -void Parser::Ident(std::wstring& name) { - Expect(_ident); - name = t->val; -} - -void Parser::Type(TypeAnnotation& typ) { - TypeAnnotation typ2; TypeAtom typ3; - if (la->kind == _lbrack) { - Get(); - Type(typ2); - Expect(_rbrack); - typ = TypeAnnotation(TypeOperator::LIST, {typ2}); - } else if (StartOf(3)) { - TypeTerm(typ3); - typ = TypeAnnotation(typ3); - } else SynErr(50); -} - -void Parser::FnTag(Function* f) { - Expression tag; TagModifier mod = TagModifier::NONE; - MetaSimpExpr(tag); - if (la->kind == 34 /* "-" */) { - Get(); - TagMod(mod); - } - f->addTag(std::move(tag), mod); -} - -void Parser::BDecl(CodeScope* scope) { - Expression body; - Expect(19 /* "{" */); - while (StartOf(4)) { - if (checkAssignment()) { - VDecl(scope); - Expect(20 /* ";" */); - } else if (la->kind == 12 /* ":" */) { - TagsDecl(scope); - Expect(20 /* ";" */); - } else { - Expr(body); - Expect(20 /* ";" */); - scope->setBody(body); - } - } - Expect(21 /* "}" */); -} - -void Parser::TypeTerm(TypeAtom& typ) { - if (la->kind == 14 /* "string" */) { - Get(); - } else if (la->kind == 15 /* "int" */) { - Get(); - } else if (la->kind == 16 /* "num" */) { - Get(); - } else if (la->kind == 17 /* "float" */) { - Get(); - } else if (la->kind == 18 /* "bool" */) { - Get(); - } else SynErr(51); - typ = Atom(t->val); -} - -void Parser::VDecl(CodeScope* f) { - std::wstring vname; Expression e; TypeAnnotation typ; - Ident(vname); - Expect(_assign); - if (la->kind == _lbrack) { - ListLiteral(e); - Expect(12 /* ":" */); - Type(typ); - } else if (la->kind == 24 /* "loop" */) { - LoopDecl(e, typ, f); - } else if (la->kind == 22 /* "if" */) { - IfDecl(e, f, typ); - } else if (StartOf(5)) { - Expr(e); - Expect(12 /* ":" */); - Type(typ); - } else SynErr(52); - f->addDeclaration(move(vname), move(typ), move(e)); -} - -void Parser::ListLiteral(Expression& e) { - Expression eFrom, eTo; - Expect(_lbrack); - if (StartOf(5)) { - Expr(eFrom); - e.addArg(std::move(eFrom)); - if (la->kind == 42 /* ".." */) { - Get(); - Expr(eTo); - e.addArg(std::move(eTo)); e.setOp(Operator::LIST_RANGE); - } else if (la->kind == _rbrack || la->kind == 13 /* "," */) { - while (la->kind == 13 /* "," */) { - Get(); - Expr(eFrom); - e.addArg(std::move(eFrom)); - } - e.setOp(Operator::LIST); - } else SynErr(53); - } - Expect(_rbrack); -} - -void Parser::LoopDecl(Expression& e, TypeAnnotation& typOut, CodeScope* f) { - std::wstring varIn, varEl, varAcc; TypeAnnotation typEl, typAcc; Expression eAcc; - ManagedScpPtr block = root.add(new xreate::CodeScope(f)); - Expect(24 /* "loop" */); - if (la->kind == 25 /* "map" */) { - Get(); - Expect(_lparen); - Ident(varIn); - Expect(_implic); - Ident(varEl); - Expect(12 /* ":" */); - Type(typEl); - Expect(_rparen); - Expect(12 /* ":" */); - Type(typOut); - BDecl(&*block); - e = Expression(Operator::MAP, {Expression(Atom(varIn))}); - e.addBindings({Atom(varEl)}); - block->addArg(Atom(varEl), move(typEl)); - e.addBlock(block); - } else if (la->kind == 26 /* "fold" */) { - Get(); - Expect(_lparen); - Ident(varIn); - Expect(_implic); - Ident(varEl); - Expect(12 /* ":" */); - Type(typEl); - Expect(13 /* "," */); - Expr(eAcc); - Expect(_implic); - Ident(varAcc); - Expect(12 /* ":" */); - Type(typAcc); - Expect(_rparen); - Expect(12 /* ":" */); - Type(typOut); - BDecl(&*block); - e = Expression(Operator::FOLD, {Expression(Atom(varIn)), eAcc}); - e.addBindings({Atom(varEl), Atom(varAcc)}); - block->addArg(Atom(varEl), move(typEl)); - block->addArg(Atom(varAcc), move(typAcc)); - e.addBlock(block); - - } else SynErr(54); -} - -void Parser::IfDecl(Expression& e, CodeScope* outer, TypeAnnotation typ) { - Expression cond; ManagedScpPtr blockTrue = root.add(new xreate::CodeScope(outer)); ManagedScpPtr blockFalse = root.add(new xreate::CodeScope(outer)); - TypeAnnotation typIf; - Expect(22 /* "if" */); - Expect(_lparen); - Expr(cond); - Expect(_rparen); - Expect(12 /* ":" */); - Type(typIf); - BDecl(&*blockTrue); - Expect(23 /* "else" */); - BDecl(&*blockFalse); - e = Expression(Operator::IF, {cond}); e.addBlock(blockTrue); e.addBlock(blockFalse); -} - -void Parser::Expr(Expression& e) { - Operator op; Expression e2; - SimExpr(e); - if (la->kind == _equal || la->kind == 46 /* "<" */ || la->kind == 47 /* ">" */) { - RelOp(op); - SimExpr(e2); - e = Expression(op, {e, e2}); - } -} - -void Parser::TagsDecl(CodeScope* f) { - Expression tag; TagModifier mod = TagModifier::NONE; - Expect(12 /* ":" */); - while (la->kind == _ident || la->kind == 34 /* "-" */) { - MetaSimpExpr(tag); - if (la->kind == 34 /* "-" */) { - Get(); - TagMod(mod); - } - - } -} - -void Parser::InDecl() { - Operator op; Expression tag; - Expression scheme; - std::vector& tags = scheme.operands; - tags.push_back(Expression()); /* return value */ - Expect(30 /* "operator" */); - InAlias(op); - Expect(12 /* ":" */); - Expect(_lparen); - scheme.setOp(op); - if (la->kind == _ident || la->kind == 34 /* "-" */) { - MetaSimpExpr(tag); - tags.push_back(tag); - while (la->kind == 13 /* "," */) { - Get(); - MetaSimpExpr(tag); - tags.push_back(tag); - } - } - Expect(_rparen); - if (la->kind == _implic) { - Get(); - MetaSimpExpr(tag); - tags[0] = tag; - } - root.addDFAData(move(scheme)); - Expect(20 /* ";" */); -} - -void Parser::InAlias(Operator& op) { - if (la->kind == 25 /* "map" */) { - Get(); - op = Operator::MAP; - } else if (la->kind == 31 /* "list_range" */) { - Get(); - op = Operator::LIST_RANGE; - } else if (la->kind == 32 /* "list" */) { - Get(); - op = Operator::LIST; - } else if (la->kind == 26 /* "fold" */) { - Get(); - op = Operator::FOLD; - } else if (la->kind == 33 /* "index" */) { - Get(); - op = Operator::INDEX; - } else SynErr(55); -} - -void Parser::MetaSimpExpr(Expression& e) { - std::wstring i1, infix; Expression e2; - if (la->kind == 34 /* "-" */) { - Get(); - MetaSimpExpr(e2); - e = Expression(Operator::NEG, {e2}); - } else if (checkParametersList()) { - Ident(i1); - e = Expression(Operator::CALL, {Expression(Atom(i1))}); - Expect(_lparen); - if (StartOf(5)) { - CalleeParams(e); - } - Expect(_rparen); - } else if (checkInfix()) { - Ident(i1); - Ident(infix); - MetaSimpExpr(e2); - e = Expression(Operator::CALL, {Expression(Atom(infix))}); - e.addArg(Expression(Atom(i1))); - e.addArg(std::move(e2)); - - } else if (la->kind == _ident) { - Ident(i1); - e = Expression(Atom(i1)); - } else SynErr(56); -} - -void Parser::TagMod(TagModifier& mod) { - if (la->kind == 35 /* "assert" */) { - Get(); - mod = TagModifier::ASSERT; - } else if (la->kind == 36 /* "require" */) { - Get(); - mod = TagModifier::REQUIRE; - } else SynErr(57); -} - -void Parser::Domain(DomainAnnotation& dom) { - if (la->kind == 11 /* "function" */) { - Get(); - dom = DomainAnnotation::FUNCTION; - } else if (la->kind == 39 /* "variable" */) { - Get(); - dom = DomainAnnotation::VARIABLE; - } else SynErr(58); -} - -void Parser::RGuard(RuleGuards& guards) { - Expression e; - MetaExpr(e); - guards.add(std::move(e)); -} - -void Parser::RBody(const RuleArguments& args, const RuleGuards& guards) { - Expression e; std::wstring msg; - Expect(40 /* "warning" */); - MetaExpr(e); - if (la->kind == 41 /* "message" */) { - Get(); - Expect(_string); - msg = t->val; - } - root.add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); -} - -void Parser::MetaExpr(Expression& e) { - Operator op; Expression e2; - MetaExpr2(e); - if (la->kind == _implic) { - MetaOp(op); - MetaExpr2(e2); - e = Expression(op, {e, e2}); - } -} - -void Parser::MetaExpr2(Expression& e) { - if (la->kind == _lparen) { - Get(); - MetaExpr(e); - Expect(_rparen); - } else if (la->kind == _ident || la->kind == 34 /* "-" */) { - MetaSimpExpr(e); - } else SynErr(59); -} - -void Parser::MetaOp(Operator& op) { - Expect(_implic); - op = Operator::IMPL; -} - -void Parser::CalleeParams(Expression& e) { - Expression e2; - Expr(e2); - e.addArg(std::move(e2)); - while (la->kind == 13 /* "," */) { - Get(); - Expr(e2); - e.addArg(std::move(e2)); - } -} - -void Parser::SimExpr(Expression& e) { - Operator op; Expression e2; - Term(e); - while (la->kind == 34 /* "-" */ || la->kind == 43 /* "+" */) { - AddOp(op); - Term(e2); - e = Expression(op, {e, e2}); - } -} - -void Parser::RelOp(Operator& op) { - op = Operator::EQU; - if (la->kind == _equal) { - Get(); - } else if (la->kind == 46 /* "<" */) { - Get(); - op = Operator::LSS; - } else if (la->kind == 47 /* ">" */) { - Get(); - op = Operator::GTR; - } else SynErr(60); -} - -void Parser::Term(Expression& e) { - Operator op; Expression e2; - Factor(e); - while (la->kind == 44 /* "*" */ || la->kind == 45 /* "/" */) { - MulOp(op); - Factor(e2); - e = Expression(op, {e, e2}); - } -} - -void Parser::AddOp(Operator& op) { - op = Operator::ADD; - if (la->kind == 43 /* "+" */) { - Get(); - } else if (la->kind == 34 /* "-" */) { - Get(); - op = Operator::SUB; - } else SynErr(61); -} - -void Parser::Factor(Expression& e) { - std::wstring name; - if (checkParametersList()) { - Ident(name); - e = Expression(Operator::CALL, {Atom(name)}); - Expect(_lparen); - if (StartOf(5)) { - CalleeParams(e); - } - Expect(_rparen); - } else if (checkIndex()) { - Ident(name); - e = Expression(Operator::INDEX, {Atom(name)}); - Expect(_lbrack); - CalleeParams(e); - Expect(_rbrack); - } else if (la->kind == _ident) { - Ident(name); - e = Expression(Atom(name)); - } else if (la->kind == _number) { - Get(); - e = Expression(Atom(t->val)); - } else if (la->kind == 34 /* "-" */) { - Get(); - Factor(e); - e = Expression(Operator::NEG, {e}); - } else if (la->kind == _lparen) { - Get(); - Expr(e); - Expect(_rparen); - } else SynErr(62); -} - -void Parser::MulOp(Operator& op) { - op = Operator::MUL; - if (la->kind == 44 /* "*" */) { - Get(); - } else if (la->kind == 45 /* "/" */) { - Get(); - op = Operator::DIV; - } else SynErr(63); -} - - - - -// If the user declared a method Init and a mehtod Destroy they should -// be called in the contructur and the destructor respctively. -// -// The following templates are used to recognize if the user declared -// the methods Init and Destroy. - -template -struct ParserInitExistsRecognizer { - template - struct ExistsIfInitIsDefinedMarker{}; - - struct InitIsMissingType { - char dummy1; - }; - - struct InitExistsType { - char dummy1; char dummy2; - }; - - // exists always - template - static InitIsMissingType is_here(...); - - // exist only if ExistsIfInitIsDefinedMarker is defined - template - static InitExistsType is_here(ExistsIfInitIsDefinedMarker*); - - enum { InitExists = (sizeof(is_here(NULL)) == sizeof(InitExistsType)) }; -}; - -template -struct ParserDestroyExistsRecognizer { - template - struct ExistsIfDestroyIsDefinedMarker{}; - - struct DestroyIsMissingType { - char dummy1; - }; - - struct DestroyExistsType { - char dummy1; char dummy2; - }; - - // exists always - template - static DestroyIsMissingType is_here(...); - - // exist only if ExistsIfDestroyIsDefinedMarker is defined - template - static DestroyExistsType is_here(ExistsIfDestroyIsDefinedMarker*); - - enum { DestroyExists = (sizeof(is_here(NULL)) == sizeof(DestroyExistsType)) }; -}; - -// The folloing templates are used to call the Init and Destroy methods if they exist. - -// Generic case of the ParserInitCaller, gets used if the Init method is missing -template::InitExists> -struct ParserInitCaller { - static void CallInit(T *t) { - // nothing to do - } -}; - -// True case of the ParserInitCaller, gets used if the Init method exists -template -struct ParserInitCaller { - static void CallInit(T *t) { - t->Init(); - } -}; - -// Generic case of the ParserDestroyCaller, gets used if the Destroy method is missing -template::DestroyExists> -struct ParserDestroyCaller { - static void CallDestroy(T *t) { - // nothing to do - } -}; - -// True case of the ParserDestroyCaller, gets used if the Destroy method exists -template -struct ParserDestroyCaller { - static void CallDestroy(T *t) { - t->Destroy(); - } -}; - -void Parser::Parse() { - t = NULL; - la = dummyToken = new Token(); - la->val = coco_string_create(L"Dummy Token"); - Get(); - Xreate(); - Expect(0); -} - -Parser::Parser(Scanner *scanner) { - maxT = 48; - - ParserInitCaller::CallInit(this); - dummyToken = NULL; - t = la = NULL; - minErrDist = 2; - errDist = minErrDist; - this->scanner = scanner; - errors = new Errors(); -} - -bool Parser::StartOf(int s) { - const bool T = true; - const bool x = false; - - static bool set[6][50] = { - {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, - {x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,T,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x}, - {x,x,x,x, x,x,T,x, x,x,x,x, x,x,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, - {x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, - {x,T,T,x, T,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, - {x,T,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x} - }; - - - - return set[s][la->kind]; -} - -Parser::~Parser() { - ParserDestroyCaller::CallDestroy(this); - delete errors; - delete dummyToken; -} - -Errors::Errors() { - count = 0; -} - -void Errors::SynErr(int line, int col, int n) { - wchar_t* s; - switch (n) { - case 0: s = coco_string_create(L"EOF expected"); break; - case 1: s = coco_string_create(L"ident expected"); break; - case 2: s = coco_string_create(L"number expected"); break; - case 3: s = coco_string_create(L"string expected"); break; - case 4: s = coco_string_create(L"lparen expected"); break; - case 5: s = coco_string_create(L"rparen expected"); break; - case 6: s = coco_string_create(L"lbrack expected"); break; - case 7: s = coco_string_create(L"rbrack expected"); break; - case 8: s = coco_string_create(L"equal expected"); break; - case 9: s = coco_string_create(L"assign expected"); break; - case 10: s = coco_string_create(L"implic expected"); break; - case 11: s = coco_string_create(L"\"function\" expected"); break; - case 12: s = coco_string_create(L"\":\" expected"); break; - case 13: s = coco_string_create(L"\",\" expected"); break; - case 14: s = coco_string_create(L"\"string\" expected"); break; - case 15: s = coco_string_create(L"\"int\" expected"); break; - case 16: s = coco_string_create(L"\"num\" expected"); break; - case 17: s = coco_string_create(L"\"float\" expected"); break; - case 18: s = coco_string_create(L"\"bool\" expected"); break; - case 19: s = coco_string_create(L"\"{\" expected"); break; - case 20: s = coco_string_create(L"\";\" expected"); break; - case 21: s = coco_string_create(L"\"}\" expected"); break; - case 22: s = coco_string_create(L"\"if\" expected"); break; - case 23: s = coco_string_create(L"\"else\" expected"); break; - case 24: s = coco_string_create(L"\"loop\" expected"); break; - case 25: s = coco_string_create(L"\"map\" expected"); break; - case 26: s = coco_string_create(L"\"fold\" expected"); break; - case 27: s = coco_string_create(L"\"import\" expected"); break; - case 28: s = coco_string_create(L"\"raw\" expected"); break; - case 29: s = coco_string_create(L"\"pass\" expected"); break; - case 30: s = coco_string_create(L"\"operator\" expected"); break; - case 31: s = coco_string_create(L"\"list_range\" expected"); break; - case 32: s = coco_string_create(L"\"list\" expected"); break; - case 33: s = coco_string_create(L"\"index\" expected"); break; - case 34: s = coco_string_create(L"\"-\" expected"); break; - case 35: s = coco_string_create(L"\"assert\" expected"); break; - case 36: s = coco_string_create(L"\"require\" expected"); break; - case 37: s = coco_string_create(L"\"rule\" expected"); break; - case 38: s = coco_string_create(L"\"case\" expected"); break; - case 39: s = coco_string_create(L"\"variable\" expected"); break; - case 40: s = coco_string_create(L"\"warning\" expected"); break; - case 41: s = coco_string_create(L"\"message\" expected"); break; - case 42: s = coco_string_create(L"\"..\" expected"); break; - case 43: s = coco_string_create(L"\"+\" expected"); break; - case 44: s = coco_string_create(L"\"*\" expected"); break; - case 45: s = coco_string_create(L"\"/\" expected"); break; - case 46: s = coco_string_create(L"\"<\" expected"); break; - case 47: s = coco_string_create(L"\">\" expected"); break; - case 48: s = coco_string_create(L"??? expected"); break; - case 49: s = coco_string_create(L"invalid FDecl"); break; - case 50: s = coco_string_create(L"invalid Type"); break; - case 51: s = coco_string_create(L"invalid TypeTerm"); break; - case 52: s = coco_string_create(L"invalid VDecl"); break; - case 53: s = coco_string_create(L"invalid ListLiteral"); break; - case 54: s = coco_string_create(L"invalid LoopDecl"); break; - case 55: s = coco_string_create(L"invalid InAlias"); break; - case 56: s = coco_string_create(L"invalid MetaSimpExpr"); break; - case 57: s = coco_string_create(L"invalid TagMod"); break; - case 58: s = coco_string_create(L"invalid Domain"); break; - case 59: s = coco_string_create(L"invalid MetaExpr2"); break; - case 60: s = coco_string_create(L"invalid RelOp"); break; - case 61: s = coco_string_create(L"invalid AddOp"); break; - case 62: s = coco_string_create(L"invalid Factor"); break; - case 63: s = coco_string_create(L"invalid MulOp"); break; - - default: - { - wchar_t format[20]; - coco_swprintf(format, 20, L"error %d", n); - s = coco_string_create(format); - } - break; - } - wprintf(L"-- line %d col %d: %ls\n", line, col, s); - coco_string_delete(s); - count++; -} - -void Errors::Error(int line, int col, const wchar_t *s) { - wprintf(L"-- line %d col %d: %ls\n", line, col, s); - count++; -} - -void Errors::Warning(int line, int col, const wchar_t *s) { - wprintf(L"-- line %d col %d: %ls\n", line, col, s); -} - -void Errors::Warning(const wchar_t *s) { - wprintf(L"%ls\n", s); -} - -void Errors::Exception(const wchar_t* s) { - wprintf(L"%ls", s); - exit(1); -} - - diff --git a/coco/Parser.h b/coco/Parser.h deleted file mode 100644 index 56d39cd..0000000 --- a/coco/Parser.h +++ /dev/null @@ -1,169 +0,0 @@ -/*---------------------------------------------------------------------- -Compiler Generator Coco/R, -Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz -extended by M. Loeberbauer & A. Woess, Univ. of Linz -ported to C++ by Csaba Balazs, University of Szeged -with improvements by Pat Terry, Rhodes University - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -As an exception, it is allowed to write an extension of Coco/R that is -used as a plugin in non-free software. - -If not otherwise stated, any source code generated by Coco/R (other than -Coco/R itself) does not fall under the GNU General Public License. ------------------------------------------------------------------------*/ - - -#if !defined(COCO_PARSER_H__) -#define COCO_PARSER_H__ - -#include "ast.h" -#include - -using namespace xreate; -using namespace std; - - -#include "Scanner.h" - - - -class Errors { -public: - int count; // number of errors detected - - Errors(); - void SynErr(int line, int col, int n); - void Error(int line, int col, const wchar_t *s); - void Warning(int line, int col, const wchar_t *s); - void Warning(const wchar_t *s); - void Exception(const wchar_t *s); - -}; // Errors - -class Parser { -private: - enum { - _EOF=0, - _ident=1, - _number=2, - _string=3, - _lparen=4, - _rparen=5, - _lbrack=6, - _rbrack=7, - _equal=8, - _assign=9, - _implic=10 - }; - int maxT; - - Token *dummyToken; - int errDist; - int minErrDist; - - void SynErr(int n); - void Get(); - void Expect(int n); - bool StartOf(int s); - void ExpectWeak(int n, int follow); - bool WeakSeparator(int n, int syFol, int repFol); - -public: - Scanner *scanner; - Errors *errors; - - Token *t; // last recognized token - Token *la; // lookahead token - -xreate::AST root; // current program unit - -bool checkParametersList() -{ - scanner->ResetPeek(); - Token* x = scanner->Peek(); - return la->kind == _ident && x->kind == _lparen; -} - -bool checkInfix() -{ - scanner->ResetPeek(); - Token* x = scanner->Peek(); - return la->kind == _ident && x->kind == _ident; -} - -bool checkIndex() -{ - scanner->ResetPeek(); - Token* x = scanner->Peek(); - return la->kind == _ident && x->kind == _lbrack; -} - -bool checkAssignment() -{ - scanner->ResetPeek(); - Token* x = scanner->Peek(); - return la->kind == _ident && x->kind == _assign; -} - - - - Parser(Scanner *scanner); - ~Parser(); - void SemErr(const wchar_t* msg); - - void Xreate(); - void FDecl(); - void RuleDecl(); - void PassData(); - void Imprt(); - void Ident(std::wstring& name); - void Type(TypeAnnotation& typ); - void FnTag(Function* f); - void BDecl(CodeScope* scope); - void TypeTerm(TypeAtom& typ); - void VDecl(CodeScope* f); - void ListLiteral(Expression& e); - void LoopDecl(Expression& e, TypeAnnotation& typOut, CodeScope* f); - void IfDecl(Expression& e, CodeScope* outer, TypeAnnotation typ); - void Expr(Expression& e); - void TagsDecl(CodeScope* f); - void InDecl(); - void InAlias(Operator& op); - void MetaSimpExpr(Expression& e); - void TagMod(TagModifier& mod); - void Domain(DomainAnnotation& dom); - void RGuard(RuleGuards& guards); - void RBody(const RuleArguments& args, const RuleGuards& guards); - void MetaExpr(Expression& e); - void MetaExpr2(Expression& e); - void MetaOp(Operator& op); - void CalleeParams(Expression& e); - void SimExpr(Expression& e); - void RelOp(Operator& op); - void Term(Expression& e); - void AddOp(Operator& op); - void Factor(Expression& e); - void MulOp(Operator& op); - - void Parse(); - -}; // end Parser - - - -#endif - diff --git a/coco/Scanner.cpp b/coco/Scanner.cpp deleted file mode 100644 index 72d3c7c..0000000 --- a/coco/Scanner.cpp +++ /dev/null @@ -1,788 +0,0 @@ -/*---------------------------------------------------------------------- -Compiler Generator Coco/R, -Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz -extended by M. Loeberbauer & A. Woess, Univ. of Linz -ported to C++ by Csaba Balazs, University of Szeged -with improvements by Pat Terry, Rhodes University - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -As an exception, it is allowed to write an extension of Coco/R that is -used as a plugin in non-free software. - -If not otherwise stated, any source code generated by Coco/R (other than -Coco/R itself) does not fall under the GNU General Public License. ------------------------------------------------------------------------*/ - - -#include -#include -#include "Scanner.h" - - - - -// string handling, wide character - - -wchar_t* coco_string_create(const wchar_t* value) { - return coco_string_create(value, 0); -} - -wchar_t* coco_string_create(const wchar_t *value, int startIndex) { - int valueLen = 0; - int len = 0; - - if (value) { - valueLen = wcslen(value); - len = valueLen - startIndex; - } - - return coco_string_create(value, startIndex, len); -} - -wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length) { - int len = 0; - wchar_t* data; - - if (value) { len = length; } - data = new wchar_t[len + 1]; - wcsncpy(data, &(value[startIndex]), len); - data[len] = 0; - - return data; -} - -wchar_t* coco_string_create_upper(const wchar_t* data) { - if (!data) { return NULL; } - - int dataLen = 0; - if (data) { dataLen = wcslen(data); } - - wchar_t *newData = new wchar_t[dataLen + 1]; - - for (int i = 0; i <= dataLen; i++) { - if ((L'a' <= data[i]) && (data[i] <= L'z')) { - newData[i] = data[i] + (L'A' - L'a'); - } - else { newData[i] = data[i]; } - } - - newData[dataLen] = L'\0'; - return newData; -} - -wchar_t* coco_string_create_lower(const wchar_t* data) { - if (!data) { return NULL; } - int dataLen = wcslen(data); - return coco_string_create_lower(data, 0, dataLen); -} - -wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen) { - if (!data) { return NULL; } - - wchar_t* newData = new wchar_t[dataLen + 1]; - - for (int i = 0; i <= dataLen; i++) { - wchar_t ch = data[startIndex + i]; - if ((L'A' <= ch) && (ch <= L'Z')) { - newData[i] = ch - (L'A' - L'a'); - } - else { newData[i] = ch; } - } - newData[dataLen] = L'\0'; - return newData; -} - -wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2) { - wchar_t* data; - int data1Len = 0; - int data2Len = 0; - - if (data1) { data1Len = wcslen(data1); } - if (data2) {data2Len = wcslen(data2); } - - data = new wchar_t[data1Len + data2Len + 1]; - - if (data1) { wcscpy(data, data1); } - if (data2) { wcscpy(data + data1Len, data2); } - - data[data1Len + data2Len] = 0; - - return data; -} - -wchar_t* coco_string_create_append(const wchar_t *target, const wchar_t appendix) { - int targetLen = coco_string_length(target); - wchar_t* data = new wchar_t[targetLen + 2]; - wcsncpy(data, target, targetLen); - data[targetLen] = appendix; - data[targetLen + 1] = 0; - return data; -} - -void coco_string_delete(wchar_t* &data) { - delete [] data; - data = NULL; -} - -int coco_string_length(const wchar_t* data) { - if (data) { return wcslen(data); } - return 0; -} - -bool coco_string_endswith(const wchar_t* data, const wchar_t *end) { - int dataLen = wcslen(data); - int endLen = wcslen(end); - return (endLen <= dataLen) && (wcscmp(data + dataLen - endLen, end) == 0); -} - -int coco_string_indexof(const wchar_t* data, const wchar_t value) { - const wchar_t* chr = wcschr(data, value); - - if (chr) { return (chr-data); } - return -1; -} - -int coco_string_lastindexof(const wchar_t* data, const wchar_t value) { - const wchar_t* chr = wcsrchr(data, value); - - if (chr) { return (chr-data); } - return -1; -} - -void coco_string_merge(wchar_t* &target, const wchar_t* appendix) { - if (!appendix) { return; } - wchar_t* data = coco_string_create_append(target, appendix); - delete [] target; - target = data; -} - -bool coco_string_equal(const wchar_t* data1, const wchar_t* data2) { - return wcscmp( data1, data2 ) == 0; -} - -int coco_string_compareto(const wchar_t* data1, const wchar_t* data2) { - return wcscmp(data1, data2); -} - -int coco_string_hash(const wchar_t *data) { - int h = 0; - if (!data) { return 0; } - while (*data != 0) { - h = (h * 7) ^ *data; - ++data; - } - if (h < 0) { h = -h; } - return h; -} - -// string handling, ascii character - -wchar_t* coco_string_create(const char* value) { - int len = 0; - if (value) { len = strlen(value); } - wchar_t* data = new wchar_t[len + 1]; - for (int i = 0; i < len; ++i) { data[i] = (wchar_t) value[i]; } - data[len] = 0; - return data; -} - -char* coco_string_create_char(const wchar_t *value) { - int len = coco_string_length(value); - char *res = new char[len + 1]; - for (int i = 0; i < len; ++i) { res[i] = (char) value[i]; } - res[len] = 0; - return res; -} - -void coco_string_delete(char* &data) { - delete [] data; - data = NULL; -} - - -Token::Token() { - kind = 0; - pos = 0; - col = 0; - line = 0; - val = NULL; - next = NULL; -} - -Token::~Token() { - coco_string_delete(val); -} - -Buffer::Buffer(FILE* s, bool isUserStream) { -// ensure binary read on windows -#if _MSC_VER >= 1300 - _setmode(_fileno(s), _O_BINARY); -#endif - stream = s; this->isUserStream = isUserStream; - if (CanSeek()) { - fseek(s, 0, SEEK_END); - fileLen = ftell(s); - fseek(s, 0, SEEK_SET); - bufLen = (fileLen < COCO_MAX_BUFFER_LENGTH) ? fileLen : COCO_MAX_BUFFER_LENGTH; - bufStart = INT_MAX; // nothing in the buffer so far - } else { - fileLen = bufLen = bufStart = 0; - } - bufCapacity = (bufLen>0) ? bufLen : COCO_MIN_BUFFER_LENGTH; - buf = new unsigned char[bufCapacity]; - if (fileLen > 0) SetPos(0); // setup buffer to position 0 (start) - else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid - if (bufLen == fileLen && CanSeek()) Close(); -} - -Buffer::Buffer(Buffer *b) { - buf = b->buf; - bufCapacity = b->bufCapacity; - b->buf = NULL; - bufStart = b->bufStart; - bufLen = b->bufLen; - fileLen = b->fileLen; - bufPos = b->bufPos; - stream = b->stream; - b->stream = NULL; - isUserStream = b->isUserStream; -} - -Buffer::Buffer(const unsigned char* buf, int len) { - this->buf = new unsigned char[len]; - memcpy(this->buf, buf, len*sizeof(unsigned char)); - bufStart = 0; - bufCapacity = bufLen = len; - fileLen = len; - bufPos = 0; - stream = NULL; -} - -Buffer::~Buffer() { - Close(); - if (buf != NULL) { - delete [] buf; - buf = NULL; - } -} - -void Buffer::Close() { - if (!isUserStream && stream != NULL) { - fclose(stream); - stream = NULL; - } -} - -int Buffer::Read() { - if (bufPos < bufLen) { - return buf[bufPos++]; - } else if (GetPos() < fileLen) { - SetPos(GetPos()); // shift buffer start to Pos - return buf[bufPos++]; - } else if ((stream != NULL) && !CanSeek() && (ReadNextStreamChunk() > 0)) { - return buf[bufPos++]; - } else { - return EoF; - } -} - -int Buffer::Peek() { - int curPos = GetPos(); - int ch = Read(); - SetPos(curPos); - return ch; -} - -// beg .. begin, zero-based, inclusive, in byte -// end .. end, zero-based, exclusive, in byte -wchar_t* Buffer::GetString(int beg, int end) { - int len = 0; - wchar_t *buf = new wchar_t[end - beg]; - int oldPos = GetPos(); - SetPos(beg); - while (GetPos() < end) buf[len++] = (wchar_t) Read(); - SetPos(oldPos); - wchar_t *res = coco_string_create(buf, 0, len); - coco_string_delete(buf); - return res; -} - -int Buffer::GetPos() { - return bufPos + bufStart; -} - -void Buffer::SetPos(int value) { - if ((value >= fileLen) && (stream != NULL) && !CanSeek()) { - // Wanted position is after buffer and the stream - // is not seek-able e.g. network or console, - // thus we have to read the stream manually till - // the wanted position is in sight. - while ((value >= fileLen) && (ReadNextStreamChunk() > 0)); - } - - if ((value < 0) || (value > fileLen)) { - wprintf(L"--- buffer out of bounds access, position: %d\n", value); - exit(1); - } - - if ((value >= bufStart) && (value < (bufStart + bufLen))) { // already in buffer - bufPos = value - bufStart; - } else if (stream != NULL) { // must be swapped in - fseek(stream, value, SEEK_SET); - bufLen = fread(buf, sizeof(unsigned char), bufCapacity, stream); - bufStart = value; bufPos = 0; - } else { - bufPos = fileLen - bufStart; // make Pos return fileLen - } -} - -// Read the next chunk of bytes from the stream, increases the buffer -// if needed and updates the fields fileLen and bufLen. -// Returns the number of bytes read. -int Buffer::ReadNextStreamChunk() { - int free = bufCapacity - bufLen; - if (free == 0) { - // in the case of a growing input stream - // we can neither seek in the stream, nor can we - // foresee the maximum length, thus we must adapt - // the buffer size on demand. - bufCapacity = bufLen * 2; - unsigned char *newBuf = new unsigned char[bufCapacity]; - memcpy(newBuf, buf, bufLen*sizeof(unsigned char)); - delete [] buf; - buf = newBuf; - free = bufLen; - } - int read = fread(buf + bufLen, sizeof(unsigned char), free, stream); - if (read > 0) { - fileLen = bufLen = (bufLen + read); - return read; - } - // end of stream reached - return 0; -} - -bool Buffer::CanSeek() { - return (stream != NULL) && (ftell(stream) != -1); -} - -int UTF8Buffer::Read() { - int ch; - do { - ch = Buffer::Read(); - // until we find a utf8 start (0xxxxxxx or 11xxxxxx) - } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EoF)); - if (ch < 128 || ch == EoF) { - // nothing to do, first 127 chars are the same in ascii and utf8 - // 0xxxxxxx or end of file character - } else if ((ch & 0xF0) == 0xF0) { - // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - int c1 = ch & 0x07; ch = Buffer::Read(); - int c2 = ch & 0x3F; ch = Buffer::Read(); - int c3 = ch & 0x3F; ch = Buffer::Read(); - int c4 = ch & 0x3F; - ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4; - } else if ((ch & 0xE0) == 0xE0) { - // 1110xxxx 10xxxxxx 10xxxxxx - int c1 = ch & 0x0F; ch = Buffer::Read(); - int c2 = ch & 0x3F; ch = Buffer::Read(); - int c3 = ch & 0x3F; - ch = (((c1 << 6) | c2) << 6) | c3; - } else if ((ch & 0xC0) == 0xC0) { - // 110xxxxx 10xxxxxx - int c1 = ch & 0x1F; ch = Buffer::Read(); - int c2 = ch & 0x3F; - ch = (c1 << 6) | c2; - } - return ch; -} - -Scanner::Scanner(const unsigned char* buf, int len) { - buffer = new Buffer(buf, len); - Init(); -} - -Scanner::Scanner(const wchar_t* fileName) { - FILE* stream; - char *chFileName = coco_string_create_char(fileName); - if ((stream = fopen(chFileName, "rb")) == NULL) { - wprintf(L"--- Cannot open file %ls\n", fileName); - exit(1); - } - coco_string_delete(chFileName); - buffer = new Buffer(stream, false); - Init(); -} - -Scanner::Scanner(FILE* s) { - buffer = new Buffer(s, true); - Init(); -} - -Scanner::~Scanner() { - char* cur = (char*) firstHeap; - - while(cur != NULL) { - cur = *(char**) (cur + COCO_HEAP_BLOCK_SIZE); - free(firstHeap); - firstHeap = cur; - } - delete [] tval; - delete buffer; -} - -void Scanner::Init() { - EOL = '\n'; - eofSym = 0; - maxT = 48; - noSym = 48; - int i; - for (i = 65; i <= 90; ++i) start.set(i, 1); - for (i = 97; i <= 122; ++i) start.set(i, 1); - for (i = 48; i <= 57; ++i) start.set(i, 2); - start.set(34, 3); - start.set(40, 5); - start.set(41, 6); - start.set(91, 7); - start.set(93, 8); - start.set(61, 11); - start.set(45, 24); - start.set(58, 12); - start.set(44, 13); - start.set(123, 14); - start.set(59, 15); - start.set(125, 16); - start.set(46, 17); - start.set(43, 19); - start.set(42, 20); - start.set(47, 21); - start.set(60, 22); - start.set(62, 23); - start.set(Buffer::EoF, -1); - keywords.set(L"function", 11); - keywords.set(L"string", 14); - keywords.set(L"int", 15); - keywords.set(L"num", 16); - keywords.set(L"float", 17); - keywords.set(L"bool", 18); - keywords.set(L"if", 22); - keywords.set(L"else", 23); - keywords.set(L"loop", 24); - keywords.set(L"map", 25); - keywords.set(L"fold", 26); - keywords.set(L"import", 27); - keywords.set(L"raw", 28); - keywords.set(L"pass", 29); - keywords.set(L"operator", 30); - keywords.set(L"list_range", 31); - keywords.set(L"list", 32); - keywords.set(L"index", 33); - keywords.set(L"assert", 35); - keywords.set(L"require", 36); - keywords.set(L"rule", 37); - keywords.set(L"case", 38); - keywords.set(L"variable", 39); - keywords.set(L"warning", 40); - keywords.set(L"message", 41); - - - tvalLength = 128; - tval = new wchar_t[tvalLength]; // text of current token - - // COCO_HEAP_BLOCK_SIZE byte heap + pointer to next heap block - heap = malloc(COCO_HEAP_BLOCK_SIZE + sizeof(void*)); - firstHeap = heap; - heapEnd = (void**) (((char*) heap) + COCO_HEAP_BLOCK_SIZE); - *heapEnd = 0; - heapTop = heap; - if (sizeof(Token) > COCO_HEAP_BLOCK_SIZE) { - wprintf(L"--- Too small COCO_HEAP_BLOCK_SIZE\n"); - exit(1); - } - - pos = -1; line = 1; col = 0; charPos = -1; - oldEols = 0; - NextCh(); - if (ch == 0xEF) { // check optional byte order mark for UTF-8 - NextCh(); int ch1 = ch; - NextCh(); int ch2 = ch; - if (ch1 != 0xBB || ch2 != 0xBF) { - wprintf(L"Illegal byte order mark at start of file"); - exit(1); - } - Buffer *oldBuf = buffer; - buffer = new UTF8Buffer(buffer); col = 0; charPos = -1; - delete oldBuf; oldBuf = NULL; - NextCh(); - } - - - pt = tokens = CreateToken(); // first token is a dummy -} - -void Scanner::NextCh() { - if (oldEols > 0) { ch = EOL; oldEols--; } - else { - pos = buffer->GetPos(); - // buffer reads unicode chars, if UTF8 has been detected - ch = buffer->Read(); col++; charPos++; - // replace isolated '\r' by '\n' in order to make - // eol handling uniform across Windows, Unix and Mac - if (ch == L'\r' && buffer->Peek() != L'\n') ch = EOL; - if (ch == EOL) { line++; col = 0; } - } - -} - -void Scanner::AddCh() { - if (tlen >= tvalLength) { - tvalLength *= 2; - wchar_t *newBuf = new wchar_t[tvalLength]; - memcpy(newBuf, tval, tlen*sizeof(wchar_t)); - delete [] tval; - tval = newBuf; - } - if (ch != Buffer::EoF) { - tval[tlen++] = ch; - NextCh(); - } -} - - -bool Scanner::Comment0() { - int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos; - NextCh(); - if (ch == L'/') { - NextCh(); - for(;;) { - if (ch == 10) { - level--; - if (level == 0) { oldEols = line - line0; NextCh(); return true; } - NextCh(); - } else if (ch == buffer->EoF) return false; - else NextCh(); - } - } else { - buffer->SetPos(pos0); NextCh(); line = line0; col = col0; charPos = charPos0; - } - return false; -} - -bool Scanner::Comment1() { - int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos; - NextCh(); - if (ch == L'*') { - NextCh(); - for(;;) { - if (ch == L'*') { - NextCh(); - if (ch == L'/') { - level--; - if (level == 0) { oldEols = line - line0; NextCh(); return true; } - NextCh(); - } - } else if (ch == L'/') { - NextCh(); - if (ch == L'*') { - level++; NextCh(); - } - } else if (ch == buffer->EoF) return false; - else NextCh(); - } - } else { - buffer->SetPos(pos0); NextCh(); line = line0; col = col0; charPos = charPos0; - } - return false; -} - - -void Scanner::CreateHeapBlock() { - void* newHeap; - char* cur = (char*) firstHeap; - - while(((char*) tokens < cur) || ((char*) tokens > (cur + COCO_HEAP_BLOCK_SIZE))) { - cur = *((char**) (cur + COCO_HEAP_BLOCK_SIZE)); - free(firstHeap); - firstHeap = cur; - } - - // COCO_HEAP_BLOCK_SIZE byte heap + pointer to next heap block - newHeap = malloc(COCO_HEAP_BLOCK_SIZE + sizeof(void*)); - *heapEnd = newHeap; - heapEnd = (void**) (((char*) newHeap) + COCO_HEAP_BLOCK_SIZE); - *heapEnd = 0; - heap = newHeap; - heapTop = heap; -} - -Token* Scanner::CreateToken() { - Token *t; - if (((char*) heapTop + (int) sizeof(Token)) >= (char*) heapEnd) { - CreateHeapBlock(); - } - t = (Token*) heapTop; - heapTop = (void*) ((char*) heapTop + sizeof(Token)); - t->val = NULL; - t->next = NULL; - return t; -} - -void Scanner::AppendVal(Token *t) { - int reqMem = (tlen + 1) * sizeof(wchar_t); - if (((char*) heapTop + reqMem) >= (char*) heapEnd) { - if (reqMem > COCO_HEAP_BLOCK_SIZE) { - wprintf(L"--- Too long token value\n"); - exit(1); - } - CreateHeapBlock(); - } - t->val = (wchar_t*) heapTop; - heapTop = (void*) ((char*) heapTop + reqMem); - - wcsncpy(t->val, tval, tlen); - t->val[tlen] = L'\0'; -} - -Token* Scanner::NextToken() { - while (ch == ' ' || - (ch >= 9 && ch <= 10) || ch == 13 - ) NextCh(); - if ((ch == L'/' && Comment0()) || (ch == L'/' && Comment1())) return NextToken(); - int recKind = noSym; - int recEnd = pos; - t = CreateToken(); - t->pos = pos; t->col = col; t->line = line; t->charPos = charPos; - int state = start.state(ch); - tlen = 0; AddCh(); - - switch (state) { - case -1: { t->kind = eofSym; break; } // NextCh already done - case 0: { - case_0: - if (recKind != noSym) { - tlen = recEnd - t->pos; - SetScannerBehindT(); - } - t->kind = recKind; break; - } // NextCh already done - case 1: - case_1: - recEnd = pos; recKind = 1; - if ((ch >= L'0' && ch <= L'9') || (ch >= L'A' && ch <= L'Z') || ch == L'_' || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_1;} - else {t->kind = 1; wchar_t *literal = coco_string_create(tval, 0, tlen); t->kind = keywords.get(literal, t->kind); coco_string_delete(literal); break;} - case 2: - case_2: - recEnd = pos; recKind = 2; - if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_2;} - else {t->kind = 2; break;} - case 3: - case_3: - if (ch <= L'!' || (ch >= L'#' && ch <= 65535)) {AddCh(); goto case_3;} - else if (ch == L'"') {AddCh(); goto case_4;} - else {goto case_0;} - case 4: - case_4: - {t->kind = 3; break;} - case 5: - {t->kind = 4; break;} - case 6: - {t->kind = 5; break;} - case 7: - {t->kind = 6; break;} - case 8: - {t->kind = 7; break;} - case 9: - case_9: - {t->kind = 8; break;} - case 10: - case_10: - {t->kind = 10; break;} - case 11: - recEnd = pos; recKind = 9; - if (ch == L'=') {AddCh(); goto case_9;} - else {t->kind = 9; break;} - case 12: - {t->kind = 12; break;} - case 13: - {t->kind = 13; break;} - case 14: - {t->kind = 19; break;} - case 15: - {t->kind = 20; break;} - case 16: - {t->kind = 21; break;} - case 17: - if (ch == L'.') {AddCh(); goto case_18;} - else {goto case_0;} - case 18: - case_18: - {t->kind = 42; break;} - case 19: - {t->kind = 43; break;} - case 20: - {t->kind = 44; break;} - case 21: - {t->kind = 45; break;} - case 22: - {t->kind = 46; break;} - case 23: - {t->kind = 47; break;} - case 24: - recEnd = pos; recKind = 34; - if (ch == L'>') {AddCh(); goto case_10;} - else {t->kind = 34; break;} - - } - AppendVal(t); - return t; -} - -void Scanner::SetScannerBehindT() { - buffer->SetPos(t->pos); - NextCh(); - line = t->line; col = t->col; charPos = t->charPos; - for (int i = 0; i < tlen; i++) NextCh(); -} - -// get the next token (possibly a token already seen during peeking) -Token* Scanner::Scan() { - if (tokens->next == NULL) { - return pt = tokens = NextToken(); - } else { - pt = tokens = tokens->next; - return tokens; - } -} - -// peek for the next token, ignore pragmas -Token* Scanner::Peek() { - do { - if (pt->next == NULL) { - pt->next = NextToken(); - } - pt = pt->next; - } while (pt->kind > maxT); // skip pragmas - - return pt; -} - -// make sure that peeking starts at the current scan position -void Scanner::ResetPeek() { - pt = tokens; -} - - diff --git a/coco/Scanner.h b/coco/Scanner.h deleted file mode 100644 index 9defd77..0000000 --- a/coco/Scanner.h +++ /dev/null @@ -1,289 +0,0 @@ -/*---------------------------------------------------------------------- -Compiler Generator Coco/R, -Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz -extended by M. Loeberbauer & A. Woess, Univ. of Linz -ported to C++ by Csaba Balazs, University of Szeged -with improvements by Pat Terry, Rhodes University - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -As an exception, it is allowed to write an extension of Coco/R that is -used as a plugin in non-free software. - -If not otherwise stated, any source code generated by Coco/R (other than -Coco/R itself) does not fall under the GNU General Public License. ------------------------------------------------------------------------*/ - - -#if !defined(COCO_SCANNER_H__) -#define COCO_SCANNER_H__ - -#include -#include -#include -#include -#include - -// io.h and fcntl are used to ensure binary read from streams on windows -#if _MSC_VER >= 1300 -#include -#include -#endif - -#if _MSC_VER >= 1400 -#define coco_swprintf swprintf_s -#elif _MSC_VER >= 1300 -#define coco_swprintf _snwprintf -#elif defined __MINGW32__ -#define coco_swprintf _snwprintf -#else -// assume every other compiler knows swprintf -#define coco_swprintf swprintf -#endif - -#define COCO_WCHAR_MAX 65535 -#define COCO_MIN_BUFFER_LENGTH 1024 -#define COCO_MAX_BUFFER_LENGTH (64*COCO_MIN_BUFFER_LENGTH) -#define COCO_HEAP_BLOCK_SIZE (64*1024) -#define COCO_CPP_NAMESPACE_SEPARATOR L':' - - - -// string handling, wide character -wchar_t* coco_string_create(const wchar_t *value); -wchar_t* coco_string_create(const wchar_t *value, int startIndex); -wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length); -wchar_t* coco_string_create_upper(const wchar_t* data); -wchar_t* coco_string_create_lower(const wchar_t* data); -wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen); -wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2); -wchar_t* coco_string_create_append(const wchar_t* data, const wchar_t value); -void coco_string_delete(wchar_t* &data); -int coco_string_length(const wchar_t* data); -bool coco_string_endswith(const wchar_t* data, const wchar_t *value); -int coco_string_indexof(const wchar_t* data, const wchar_t value); -int coco_string_lastindexof(const wchar_t* data, const wchar_t value); -void coco_string_merge(wchar_t* &data, const wchar_t* value); -bool coco_string_equal(const wchar_t* data1, const wchar_t* data2); -int coco_string_compareto(const wchar_t* data1, const wchar_t* data2); -int coco_string_hash(const wchar_t* data); - -// string handling, ascii character -wchar_t* coco_string_create(const char *value); -char* coco_string_create_char(const wchar_t *value); -void coco_string_delete(char* &data); - - -class Token -{ -public: - int kind; // token kind - int pos; // token position in bytes in the source text (starting at 0) - int charPos; // token position in characters in the source text (starting at 0) - int col; // token column (starting at 1) - int line; // token line (starting at 1) - wchar_t* val; // token value - Token *next; // ML 2005-03-11 Peek tokens are kept in linked list - - Token(); - ~Token(); -}; - -class Buffer { -// This Buffer supports the following cases: -// 1) seekable stream (file) -// a) whole stream in buffer -// b) part of stream in buffer -// 2) non seekable stream (network, console) -private: - unsigned char *buf; // input buffer - int bufCapacity; // capacity of buf - int bufStart; // position of first byte in buffer relative to input stream - int bufLen; // length of buffer - int fileLen; // length of input stream (may change if the stream is no file) - int bufPos; // current position in buffer - FILE* stream; // input stream (seekable) - bool isUserStream; // was the stream opened by the user? - - int ReadNextStreamChunk(); - bool CanSeek(); // true if stream can be seeked otherwise false - -public: - static const int EoF = COCO_WCHAR_MAX + 1; - - Buffer(FILE* s, bool isUserStream); - Buffer(const unsigned char* buf, int len); - Buffer(Buffer *b); - virtual ~Buffer(); - - virtual void Close(); - virtual int Read(); - virtual int Peek(); - virtual wchar_t* GetString(int beg, int end); - virtual int GetPos(); - virtual void SetPos(int value); -}; - -class UTF8Buffer : public Buffer { -public: - UTF8Buffer(Buffer *b) : Buffer(b) {}; - virtual int Read(); -}; - -//----------------------------------------------------------------------------------- -// StartStates -- maps characters to start states of tokens -//----------------------------------------------------------------------------------- -class StartStates { -private: - class Elem { - public: - int key, val; - Elem *next; - Elem(int key, int val) { this->key = key; this->val = val; next = NULL; } - }; - - Elem **tab; - -public: - StartStates() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); } - virtual ~StartStates() { - for (int i = 0; i < 128; ++i) { - Elem *e = tab[i]; - while (e != NULL) { - Elem *next = e->next; - delete e; - e = next; - } - } - delete [] tab; - } - - void set(int key, int val) { - Elem *e = new Elem(key, val); - int k = ((unsigned int) key) % 128; - e->next = tab[k]; tab[k] = e; - } - - int state(int key) { - Elem *e = tab[((unsigned int) key) % 128]; - while (e != NULL && e->key != key) e = e->next; - return e == NULL ? 0 : e->val; - } -}; - -//------------------------------------------------------------------------------------------- -// KeywordMap -- maps strings to integers (identifiers to keyword kinds) -//------------------------------------------------------------------------------------------- -class KeywordMap { -private: - class Elem { - public: - wchar_t *key; - int val; - Elem *next; - Elem(const wchar_t *key, int val) { this->key = coco_string_create(key); this->val = val; next = NULL; } - virtual ~Elem() { coco_string_delete(key); } - }; - - Elem **tab; - -public: - KeywordMap() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); } - virtual ~KeywordMap() { - for (int i = 0; i < 128; ++i) { - Elem *e = tab[i]; - while (e != NULL) { - Elem *next = e->next; - delete e; - e = next; - } - } - delete [] tab; - } - - void set(const wchar_t *key, int val) { - Elem *e = new Elem(key, val); - int k = coco_string_hash(key) % 128; - e->next = tab[k]; tab[k] = e; - } - - int get(const wchar_t *key, int defaultVal) { - Elem *e = tab[coco_string_hash(key) % 128]; - while (e != NULL && !coco_string_equal(e->key, key)) e = e->next; - return e == NULL ? defaultVal : e->val; - } -}; - -class Scanner { -private: - void *firstHeap; - void *heap; - void *heapTop; - void **heapEnd; - - unsigned char EOL; - int eofSym; - int noSym; - int maxT; - int charSetSize; - StartStates start; - KeywordMap keywords; - - Token *t; // current token - wchar_t *tval; // text of current token - int tvalLength; // length of text of current token - int tlen; // length of current token - - Token *tokens; // list of tokens already peeked (first token is a dummy) - Token *pt; // current peek token - - int ch; // current input character - - int pos; // byte position of current character - int charPos; // position by unicode characters starting with 0 - int line; // line number of current character - int col; // column number of current character - int oldEols; // EOLs that appeared in a comment; - - void CreateHeapBlock(); - Token* CreateToken(); - void AppendVal(Token *t); - void SetScannerBehindT(); - - void Init(); - void NextCh(); - void AddCh(); - bool Comment0(); - bool Comment1(); - - Token* NextToken(); - -public: - Buffer *buffer; // scanner buffer - - Scanner(const unsigned char* buf, int len); - Scanner(const wchar_t* fileName); - Scanner(FILE* s); - ~Scanner(); - Token* Scan(); - Token* Peek(); - void ResetPeek(); - -}; // end Scanner - - - -#endif - diff --git a/coco/xreate.ATG b/coco/xreate.ATG index dab9e71..44ec3ed 100644 --- a/coco/xreate.ATG +++ b/coco/xreate.ATG @@ -1,293 +1,422 @@ +//TODO add ListLiteral +//TODO ExprTyped: assign default(none) type + #include "ast.h" +#include "ExternLayer.h" #include +#define wprintf(format, ...) \ + char __buffer[100]; \ + wcstombs(__buffer, format, 100); \ + fprintf(stderr, __buffer, __VA_ARGS__) + using namespace xreate; using namespace std; COMPILER Xreate xreate::AST root; // current program unit -bool checkParametersList() +int skipIdent() { + int kind = 0; scanner->ResetPeek(); - Token* x = scanner->Peek(); - return la->kind == _ident && x->kind == _lparen; + while ((kind = scanner->Peek()->kind) == _colon) + if (scanner->Peek()->kind != _ident) + return 0; + + return kind; +} + +bool checkParametersList() +{ + return la->kind == _ident && skipIdent() == _lparen; } bool checkInfix() { - scanner->ResetPeek(); - Token* x = scanner->Peek(); - return la->kind == _ident && x->kind == _ident; + return la->kind == _ident && skipIdent() == _ident; } bool checkIndex() { - scanner->ResetPeek(); - Token* x = scanner->Peek(); - return la->kind == _ident && x->kind == _lbrack; + return la->kind == _ident && skipIdent() == _lbrack; +} + +bool checkFuncDecl() +{ + if (la->kind != _ident) return false; + + int xkind = skipIdent(); + Token* y = scanner->Peek(); + return xkind == _assign && y->kind == _function; } bool checkAssignment() { scanner->ResetPeek(); Token* x = scanner->Peek(); return la->kind == _ident && x->kind == _assign; } CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". any = ANY - '"'. digit = "0123456789". cr = '\r'. lf = '\n'. tab = '\t'. TOKENS - ident = letter {letter | digit | '_'}. + ident = (letter | '_') {letter | digit | '_'}. number = digit {digit}. string = '"' { any } '"'. + function = "function". lparen = '('. rparen = ')'. lbrack = '['. rbrack = ']'. equal = "==". assign = '='. implic = '-' '>'. + colon = ':'. + tagcolon = "::". COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS -Xreate = { ( FDecl | RuleDecl | PassData | Imprt) }. +Xreate = { ( RuleDecl | InterfaceData | Imprt | IF(checkFuncDecl()) FDecl | TDecl ) }. Ident -= ident (. name = t->val; .). += ident {':' ident} (. name = t->val; .). FDecl<> = (. std::wstring fname; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; .) -Ident assign "function" ':' (. Function* f = new Function(fname); CodeScope* entry = f->getEntryScope(); .) +Ident assign function (. Function* f = new Function(fname); CodeScope* entry = f->getEntryScope(); .) ( Type (. f->setReturnType(typOut); .) -| '(' [Ident ':' Type (. f->addArg(std::move(varname), move(typIn)); .) -{',' Ident ':' Type (. f->addArg(std::move(varname), move(typIn));.) -}] ')' implic Type (. f->setReturnType(typOut); .) -{',' FnTag } -) BDecl (. root.add(f); .) +| '(' [Ident tagcolon Type (. f->addArg(std::move(varname), move(typIn)); .) +{',' Ident tagcolon Type (. f->addArg(std::move(varname), move(typIn));.) +}] ')' tagcolon Type (. f->setReturnType(typOut); .) +{';' FnTag } +) BDecl (. entry->__body.bindType(move(typOut)); root.add(f); .) . -TypeTerm = ("string" | "int" | "num" | "float" | "bool") (. typ = Atom(t->val); .) . -Type = (. TypeAnnotation typ2; TypeAtom typ3; .) -('[' Type ']' (. typ = TypeAnnotation(TypeOperator::LIST, {typ2}); .) + /** + * TYPES + * + */ +TypeTerm = (. std::wstring tid; .) + ("string" | "int" | "num" | "float" | "bool") (. typ = Atom(t->val); .) + . + +Type = (. TypeAnnotation typ2; TypeAtom typ3; std:wstring tid, field; .) +( + TList +| TStruct | TypeTerm (. typ = TypeAnnotation(typ3); .) +|IF (checkIndex()) Ident lbrack + Ident (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(Atom(field).get()); .) + {',' Ident (. typ.fields.push_back(Atom(field).get()); .) + } rbrack + +| Ident (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom(tid).get(); .) + ['(' Type (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .) + {',' Type (. typ.__operands.push_back(typ2); .) + } ')'] ) . -VDecl = (. std::wstring vname; Expression e; TypeAnnotation typ; .) -Ident assign -(ListLiteral ':' Type -| LoopDecl -| IfDecl -| Expr ':' Type -) (. f->addDeclaration(move(vname), move(typ), move(e)); .). +TList = (. TypeAnnotation ty; .) + '[' Type (. typ = TypeAnnotation(TypeOperator::ARRAY, {ty}); .) + {',' Type (. typ.__operator = TypeOperator::TUPLE; typ.__operands.push_back(ty); .) + }']' + . + +TStruct = (. TypeAnnotation t; std::wstring field; .) + '{' + Ident tagcolon Type (. typ = TypeAnnotation(TypeOperator::STRUCT, {t}); typ.fields.push_back(Atom(field).get()); .) + {',' Ident tagcolon Type} (. typ.__operands.push_back(t); typ.fields.push_back(Atom(field).get()); .) + '}'. + + TDecl = (. std::wstring ttag; TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) + Ident assign "type" + ( + "alias" Type (. root.add(move(t), Atom(tname)); .) + | Ident + ['(' Ident (. args.push_back(Atom(arg)); .) + {',' Ident (. args.push_back(Atom(arg)); .) + } ')'] + Type (. t.addBindings(move(args)); root.add(move(t), Atom(tname)); .) + ) '.' + . + +VDecl = (. std::wstring vname; Expression e; TypeAnnotation typ;.) +Ident assign ExprTyped + (. f->addDeclaration(move(vname), move(typ), move(e)); .) +. -BDecl = (. Expression body; .) +BDecl = (. Expression body; TypeAnnotation typ; .) '{' { ( - IF(checkAssignment()) VDecl ';' - | TagsDecl ';' - | Expr ';' (. scope->setBody(body); .) + IF(checkAssignment()) VDecl '.' + | ExprTyped (. scope->setBody(body); .) )} '}'. -IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root.add(new xreate::CodeScope(outer)); ManagedScpPtr blockFalse = root.add(new xreate::CodeScope(outer)); +IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root.add(new xreate::CodeScope(outer)); ManagedScpPtr blockFalse = root.add(new xreate::CodeScope(outer)); TypeAnnotation typIf; .) -"if" '(' Expr ')' ':' Type BDecl<&*blockTrue> "else" BDecl<&*blockFalse> +"if" '(' Expr ')' tagcolon Type BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e = Expression(Operator::IF, {cond}); e.addBlock(blockTrue); e.addBlock(blockFalse); .) . LoopDecl = - (. std::wstring varIn, varEl, varAcc; TypeAnnotation typEl, typAcc; Expression eAcc; + (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc; TypeAnnotation typEl, typAcc; ManagedScpPtr block = root.add(new xreate::CodeScope(f)); .) "loop" - ("map" '(' Ident implic Ident ':' Type ')' ':' Type BDecl<&*block> - (. e = Expression(Operator::MAP, {Expression(Atom(varIn))}); + ("map" '(' Expr implic Ident tagcolon Type ')' tagcolon Type BDecl<&*block> + (. e = Expression(Operator::MAP, {eIn}); e.addBindings({Atom(varEl)}); block->addArg(Atom(varEl), move(typEl)); e.addBlock(block); .) - |"fold" '(' Ident implic Ident ':' Type ',' Expr implic Ident ':' Type ')' ':' Type BDecl<&*block> - (. e = Expression(Operator::FOLD, {Expression(Atom(varIn)), eAcc}); + |"fold" '(' Expr implic Ident tagcolon Type ['|' Expr ] ',' Expr implic Ident tagcolon Type ')' tagcolon Type BDecl<&*block> + (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); block->addArg(Atom(varEl), move(typEl)); block->addArg(Atom(varAcc), move(typAcc)); e.addBlock(block); .) ). - - /*============================ METAPROGRAMMING ===============================*/ - + +SwitchDecl<> = (. TypeAnnotation typ; Expression tag; .) + ["switch" [tagcolon Type {';' MetaSimpExpr}]] + CaseDecl {CaseDecl} +. + +CaseDecl<> = (. Expression e; .) + "case" + ( "default" + | CalleeParamsNamed + ) + + BDecl +. + + /*============================ INTERFACES ===============================*/ Imprt<> = "import" "raw" '(' string (. root.__rawImports.push_back(Atom(t->val).get()); .) -')' ';'. +')' '.' . + +InterfaceData<> = "interface" '(' + ( "dfa" ')' InterfaceDFA + | "extern-c" ')' InterfaceExternC + ). + +InterfaceExternC<> = (.xreate::ExternData data; .) + '{' {IncludeExternDecl | LibExternDecl } '}' + (. root.addExternData(move(data)); .) +. + +LibExternDecl = (. std:wstring pkgname, libname; .) + Ident assign "library" tagcolon "pkgconfig" + '(' string (. pkgname = t->val; .) + ')' '.' (. data.addLibrary(Atom(libname), Atom(pkgname)); .) +. + +IncludeExternDecl = (. Expression inc; .) + "include" StructLiteral '.' (. data.addIncludeDecl(move(inc)); .) +. + + +InterfaceDFA<> = '{' { InstructDecl } '}' . -PassData<> = -"pass" '(' ident ')' '{' { InDecl } '}' . -InDecl = (.Operator op; Expression tag; +InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) -"operator" InAlias ':' '(' (.scheme.setOp(op); .) +"operator" InstructAlias tagcolon '(' (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] ')' [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root.addDFAData(move(scheme)); .) -';'. +'.'. -InAlias = +InstructAlias = ( "map" (. op = Operator::MAP; .) | "list_range" (. op = Operator::LIST_RANGE; .) | "list" (. op = Operator::LIST; .) | "fold" (. op = Operator::FOLD; .) | "index" (. op = Operator::INDEX; .) -). +). + + + /*============================ METAPROGRAMMING ===============================*/ +// TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) +// ':' { MetaSimpExpr (. /*f.addTag(std::move(tag), mod); */ .) +// }. -TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) -':' { MetaSimpExpr ['-' TagMod] (. /*f.addTag(std::move(tag), mod); */ .) -}. FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) MetaSimpExpr ['-' TagMod] (. f->addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). RuleDecl<> = -"rule" ':' (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) -'(' Ident ':' Domain (. args.add(arg, typ); .) -{',' Ident ':'Domain (. args.add(arg, typ); .) +"rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) +'(' Ident tagcolon Domain (. args.add(arg, typ); .) +{',' Ident tagcolon Domain (. args.add(arg, typ); .) } ')' ["case" RGuard {',' RGuard}] '{' RBody '}' . Domain = ( "function" (. dom = DomainAnnotation::FUNCTION; .) | "variable" (. dom = DomainAnnotation::VARIABLE; .) ). RGuard= (. Expression e; .) MetaExpr (. guards.add(std::move(e)); .). MetaExpr= (.Operator op; Expression e2; .) MetaExpr2 [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) ]. MetaExpr2= ( '(' MetaExpr ')' | MetaSimpExpr ). MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) | IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); .) '(' [ CalleeParams ] ')' | IF(checkInfix()) Ident Ident MetaSimpExpr (. e = Expression(Operator::CALL, {Expression(Atom(infix))}); e.addArg(Expression(Atom(i1))); e.addArg(std::move(e2)); .) | Ident (. e = Expression(Atom(i1)); .) ). RBody = (. Expression e; std::wstring msg; .) "warning" MetaExpr ["message" string (. msg = t->val; .) ] (. root.add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) . MetaOp< Operator& op> = implic (. op = Operator::IMPL; .) . /*============================ Expressions ===============================*/ -// dublicates CalleeParams -ListLiteral = (. Expression eFrom, eTo; .) -'[' -[ Expr (. e.addArg(std::move(eFrom)); .) -(".." Expr (. e.addArg(std::move(eTo)); e.setOp(Operator::LIST_RANGE); .) - |{',' Expr (. e.addArg(std::move(eFrom)); .) -} (. e.setOp(Operator::LIST); .) -) ] ']'. - +ExprTyped = (. Expression tag; .) + Expr [tagcolon Type (. e.bindType(move(typ)); .) + {';' MetaSimpExpr (. e.tags.emplace(tag.getValueString(), move(tag)); .) + + }] +. Expr< Expression& e> (. Operator op; Expression e2; .) = SimExpr< e> [ RelOp< op> SimExpr< e2> (. e = Expression(op, {e, e2}); .) ]. SimExpr< Expression& e> (. Operator op; Expression e2; .) = Term< e> { AddOp< op> Term< e2> (. e = Expression(op, {e, e2});.) }. Term< Expression& e> (. Operator op; Expression e2; .) = Factor< e> { MulOp< op> Factor< e2> (. e = Expression(op, {e, e2}); .) }. -Factor< Expression& e> (. std::wstring name;.) +Factor< Expression& e> (. std::wstring name; TypeAnnotation typ; .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); .) '(' [CalleeParams] ')' - |IF (checkIndex()) Ident (. e = Expression(Operator::INDEX, {Atom(name)}); .) - lbrack CalleeParams rbrack + |IF (checkIndex()) Ident + lbrack CalleeParams rbrack (. e.setOp(Operator::INDEX); e.setValue({Atom(name)}); .) | Ident< name> (. e = Expression(Atom(name)); .) + | ListLiteral (. /* tuple */.) + | StructLiteral (. /* struct */.) + | LoopDecl + | IfDecl + | SwitchDecl | number (. e = Expression(Atom(t->val)); .) + | string (. e = Expression(Atom(t->val)); .) | '-' Factor< e> (. e = Expression(Operator::NEG, {e}); .) | '(' Expr ')' ). + +StructLiteral = (. std::wstring key; Expression val; std::list> keys; .) + '{' Ident '=' Expr (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) + {',' Ident '=' Expr (.e.addArg(move(val)); keys.push_back(Atom(key)); .) + } '}' (. e.addBindings(keys.begin(), keys.end()); .) + . + +ListLiteral = (. Expression eFrom, eTo; .) +'[' +[ Expr (. e.addArg(std::move(eFrom)); .) +(".." Expr (. e.addArg(std::move(eTo)); e.setOp(Operator::LIST_RANGE); .) + |{',' Expr (. e.addArg(std::move(eFrom)); .) +} (. e.setOp(Operator::LIST); .) +) ] ']'. -CalleeParams = (. Expression e2; .) - Expr (. e.addArg(std::move(e2)); .) - {',' Expr (. e.addArg(std::move(e2)); .) +CalleeParams = (. Expression e2; TypeAnnotation typ; .) + ExprTyped (. e.addArg(std::move(e2)); .) + {',' ExprTyped (. e.addArg(std::move(e2)); .) }. +CalleeParamsNamed<> = + CalleeParamNamed + {',' CalleeParamNamed + }. + +CalleeParamNamed<> = (. Expression arg; TypeAnnotation argtyp; .) + ( + IF(checkAssignment()) VDecl + | ExprTyped + ). + AddOp< Operator& op> = (. op = Operator::ADD; .) ( '+' | '-' (. op = Operator::SUB; .) ). MulOp< Operator& op> = (. op = Operator::MUL; .) ( '*' | '/' (. op = Operator::DIV; .) ). RelOp< Operator& op> = (. op = Operator::EQU; .) ( equal | '<' (. op = Operator::LSS; .) | '>' (. op = Operator::GTR; .) ). END Xreate. diff --git a/config/default.json b/config/default.json new file mode 100644 index 0000000..1cb116b --- /dev/null +++ b/config/default.json @@ -0,0 +1,42 @@ +{ + "containers": { + "id": { + "implementations": "impl_fulfill_cluster", + "clusters": "var_cluster", + "prototypes": "proto_cluster", + "linkedlist": "linkedlist" + }, + + "impl": { + "solid": "solid", + "onthefly": "on_the_fly" + } + }, + + "logging": { + "id": "logging" + }, + + "function-entry": "entry", + + "clasp": { + "bindings" : { + "variable": "bind", + "function": "bind_func" + } + }, + + "tests": { + "template": "default", + + "templates": { + "default": "*-", + "types": "Types*-", + "containers": "Containers*-", + "ast": "AST*", + "non-containers": "*-Containers*", + "libxml2": "libxml2*", + "log": "Logging*" + } + } +} diff --git a/core/containers.lp b/core/containers.lp index 16b5432..876c7c9 100644 --- a/core/containers.lp +++ b/core/containers.lp @@ -1,44 +1,57 @@ %defines - impl(llvm_array; llvm_const_array; on_the_fly). - op(seqaccess). op(randaccess). + impl(solid; on_the_fly; linked_list). + op(seqaccess; randaccess). relation(recommends; satisfied; unsupported). relation_score(satisfied, 0). relation_score(recommends, 1). relation_score(unsupported, -1). score(-1..1). %domain facts: relation_op(seqaccess, on_the_fly, recommends). - relation_op(randaccess, llvm_const_array, recommends). + relation_op(randaccess, solid, recommends). relation_op(randaccess, on_the_fly, unsupported). %dfa analysis: -% -- +%scheme: dfa_connection(Vto, Vfrom, proto); +%-- dfa_connection(VTo, VFrom, alias); +%-- dfa_connection(VFormal, VActual, arg); +%-- dfa_connection(VActual, VFormal, ret) %compilation: %-- %domain rules: + %aliases: + var_origin(VAR) :- not dfa_connection(VAR, _, alias), v(VAR). + var_alias(VAR0, VAR_TO) :- dfa_connection(VAR_TO, VAR0, alias), var_origin(VAR0). + var_alias(VAR0, VAR_TO2) :- dfa_connection(VAR_TO2, VAR_TO1, alias), var_alias(VAR0, VAR_TO1). + var_alias(VAR0, VAR0):- var_origin(VAR0). + + %prototypes: + var_proto(V0, Vproto) :- var_origin(V0); var_origin(Vproto); var_alias(Vproto, Vp); dfa_connection(V0, Vp, proto). + + %implementations: -impl_fulfill(OP, IMPL) :- relation_op(OP, IMPL, unsupported). impl_fulfill(OP, IMPL, SCORE):- SCORE = #sum{SCORE1, (OP, IMPL, RL): relation_op(OP, IMPL, RL),relation_score(RL, SCORE1)} ; op(OP); impl(IMPL); not -impl_fulfill(OP, IMPL). - cluster_root(VAR) :- not dfa_connection(VAR, _, strong), v(VAR). - var_cluster(VAR0, VAR_TO) :- dfa_connection(VAR_TO, VAR0, strong), cluster_root(VAR0). - var_cluster(VAR0, VAR_TO2) :- dfa_connection(VAR_TO2, VAR_TO1, strong), var_cluster(VAR0, VAR_TO1). - var_cluster(VAR0, VAR0):- cluster_root(VAR0). + -var_impl_fulfill(Var0, Impl) :- var_alias(Var0, Var_Any); bind(Var_Any, op(Op)); -impl_fulfill(Op, Impl). + var_impl_fulfill(VAR0, IMPL, Score) :- + Score = #sum{SCORE, (OP, IMPL, VAR_ANY): impl_fulfill(OP, IMPL, SCORE), var_alias(VAR0, VAR_ANY), bind(VAR_ANY, op(OP))} + ; bind(VAR0, impl(IMPL)); var_origin(VAR0); not -var_impl_fulfill(VAR0, IMPL). - -impl_fulfill_cluster(Var0, Impl) :- var_cluster(Var0, Var_Any); bind(Var_Any, op(Op)); -impl_fulfill(Op, Impl). - impl_fulfill_cluster(VAR0, IMPL, Score) :- - Score = #sum{SCORE, (OP, IMPL, VAR_ANY): impl_fulfill(OP, IMPL, SCORE), var_cluster(VAR0, VAR_ANY), bind(VAR_ANY, op(OP))} - ; bind(VAR0, impl(IMPL)); cluster_root(VAR0); not -impl_fulfill_cluster(VAR0, IMPL). - + %transfunction implementation: + %bind(Vactual, op(Op)) :- var_alias(Vformal, V1); bind(V1, op(Op)); dfa_connection(Vformal, Vactual, arg); op(Op). - proto_cluster(V0, Vproto) :- cluster_root(V0); cluster_root(Vproto); var_cluster(Vproto, Vp); dfa_connection(V0, Vp, proto). + %bind(Vactual, op(Op)) :- var_alias(VO, Vformal); var_alias(VO, V); bind(V, op(Op)); dfa_connection(Vactual,Vformal, ret); op(Op). + % --uncomment to add possible implementations(impl) to an actual var + %bind(Vres, op(Op)) :- var_alias(VO, VA); bind(VA, op(Op)); dfa_connection(VArg,VO, result); op(Op). %optimization -% #maximize {SCORE, (VAR0, IMPL) : impl_fulfill_cluster(VAR0, IMPL, SCORE)}. +% #maximize {SCORE, (VAR0, IMPL) : var_impl_fulfill(VAR0, IMPL, SCORE)}. -#show var_cluster/2. -#show impl_fulfill_cluster/3. +#show var_alias/2. +#show var_impl_fulfill/3. +#show proto_alias2. diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 16cb9ac..30040d4 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,94 +1,141 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) find_package(LLVM REQUIRED CONFIG) find_package(Qt5Core) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +set(CMAKE_BUILD_TYPE Debug) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS") set(SOURCE_FILES - ./src/ast.cpp ./src/ast-compilation.cpp + ./src/ast.cpp ./src/llvmlayer.cpp ./src/clasplayer.cpp #./src/main.cpp - ./tests/tests.cpp + ./tests/tests.cpp ./tests/testClangAPI.cpp ./tests/testJson.cpp ./tests/testBasic.cpp + ./src/utils.cpp ./src/passmanager.cpp - ./src/pass/abstractpass.cpp - ./src/pass/dfgpass.cpp - #./src/pass/cfgpass.cpp ./src/pass/functiontagspass.cpp - #./src/pass/rulespass.cpp ./src/pass/dfgpass.cpp + ./src/pass/abstractpass.cpp ./src/pass/dfgpass.cpp ./src/pass/compilepass.cpp ./src/pass/functiontagspass.cpp + #./src/pass/cfgpass.cpp + #./src/pass/rulespass.cpp src/instructions/instr-containers.cpp src/query/containers.cpp src/attachments.cpp /opt/potassco/gringo-4.4.0-source/app/shared/src/clingocontrol.cc /opt/potassco/gringo-4.4.0-source/app/pyclingo/src/clingo_lib.cc ) set(COCO_PATH ${CMAKE_HOME_DIRECTORY}/../coco/) set(COCO_SOURCE_FILES ${COCO_PATH}/Parser.h ${COCO_PATH}/Scanner.h ${COCO_PATH}/Parser.cpp ${COCO_PATH}/Scanner.cpp ) set(POTASSCO_PATH "/opt/potassco/gringo-4.4.0-source") +INCLUDE_DIRECTORIES("/usr/lib/llvm-3.7/include") +INCLUDE_DIRECTORIES("/usr/include/libxml2") +INCLUDE_DIRECTORIES("/usr/include/libxml2") INCLUDE_DIRECTORIES(${COCO_PATH} ./src) INCLUDE_DIRECTORIES(${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/app/shared/include ${POTASSCO_PATH}/app/pyclingo/src ${POTASSCO_PATH}/libprogram_opts ) - + +include_directories(${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/) + #execute_process(COMMAND ${COCO_PATH}/gen-xreate WORKING_DIRECTORY OUTPUT_VARIABLE COCO_OUTPUT) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) -add_executable(xreate ${SOURCE_FILES} ${COCO_SOURCE_FILES} ) +add_executable(xreate ${SOURCE_FILES} ${COCO_SOURCE_FILES} tests/testLibXml2.h tests/testLibXml2.cpp src/ExternLayer.cpp src/ExternLayer.h) set(COCO_TARGET cocoTarget) add_custom_target(${COCO_TARGET} WORKING_DIRECTORY ${COCO_PATH} ) add_custom_command(TARGET ${COCO_TARGET} PRE_BUILD COMMAND ${COCO_PATH}/gen-xreate WORKING_DIRECTORY ${COCO_PATH} ) -#add_dependencies(${PROJECT_NAME} ${COCO_TARGET}) +add_custom_target (coverage + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + +message(STATUS "BINARY DIR" ${CMAKE_BINARY_DIR}) -llvm_map_components_to_libnames(llvm_libs support core irreader) +#add_dependencies(${PROJECT_NAME} coverageTarget) + +llvm_map_components_to_libnames(llvm_libs support core irreader all native nativecodegen) message(STATUS "LLVM LIBS: " ${llvm_libs}) set (LIBCLASP_PATH ${POTASSCO_PATH}/build/debug) #find_library(LIBCLASP_LIBRARY_GRINGO NAMES gringo # HINTS ${LIBCLASP_PATH}) #find_library(LIBCLASP_LIBRARY_CLASP NAMES clasp # HINTS ${LIBCLASP_PATH}) set(LIBCLASP_LIBS ${LIBCLASP_PATH}/libclasp.a ${LIBCLASP_PATH}/libgringo.a ${LIBCLASP_PATH}/libprogram_opts.a ) +#set(LIBCLANG_PATH "/usr/lib/llvm-3.7/lib/") +#set(LIBCLANG_LIBS +##/usr/lib/llvm-3.7/lib/libclangToolingCore.a +#/usr/lib/llvm-3.7/lib/libclangTooling.a +#) + +file(GLOB_RECURSE LIBCLANG_LIBS2 /usr/lib/llvm-3.7/lib/*.a) + +set(LIBCLANG_LIBS +/usr/lib/llvm-3.7/lib/libclangParse.a +/usr/lib/llvm-3.7/lib/libclangFormat.a +${LIBCLANG_LIBS2} +${LIBCLANG_LIBS2} +/usr/lib/llvm-3.7/lib/libclangParse.a +/usr/lib/llvm-3.7/lib/libclangFormat.a +) + +message(STATUS "ALL LIBS: " ${LIBCLANG_LIBS}) + + message(STATUS ${LIBCLASP_LIBS}) -target_link_libraries(xreate ${llvm_libs} pthread Qt5::Core ${LIBCLASP_LIBS}) + add_definitions(-DWITH_THREADS=0) + +FUNCTION(PREPEND var prefix) + SET(listVar "") + FOREACH(f ${ARGN}) + LIST(APPEND listVar "${prefix}/${f}") + ENDFOREACH(f) + SET(${var} "${listVar}" PARENT_SCOPE) +ENDFUNCTION(PREPEND) + + +find_package(GTest REQUIRED) +INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS}) +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall -fprofile-arcs -ftest-coverage -O0") + +target_link_libraries(xreate ${GTEST_LIBRARIES} ${llvm_libs} ${LIBCLANG_LIBS} pthread xml2 Qt5::Core ${LIBCLASP_LIBS} gcov) diff --git a/cpp/code-coverage.sh b/cpp/code-coverage.sh new file mode 100755 index 0000000..a1ee2de --- /dev/null +++ b/cpp/code-coverage.sh @@ -0,0 +1,2 @@ +lcov --capture --directory ./ --output-file coverage.info +genhtml coverage.info --output-directory coverage-report diff --git a/cpp/src/ExternLayer.cpp b/cpp/src/ExternLayer.cpp new file mode 100644 index 0000000..1b95b7e --- /dev/null +++ b/cpp/src/ExternLayer.cpp @@ -0,0 +1,274 @@ +// +// Created by pgess on 4/21/15. +// + +#include "ExternLayer.h" + +#include "QStringList" +#include +#include +#include "clang/Tooling/Tooling.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CodeGenOptions.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/TargetInfo.h" +#include + +using namespace xreate; +using namespace std; +using namespace clang; +using namespace clang::driver; +using namespace clang::tooling; +using namespace clang::ast_matchers; +using namespace llvm; + + +class FinderCallbackTypeDecl : public MatchFinder::MatchCallback { +public : + QualType typeResult; + + virtual void run(const MatchFinder::MatchResult &Result) { + if (const TypedefDecl* decl = Result.Nodes.getNodeAs("typename")) { + typeResult = decl->getUnderlyingType(); + } + } +}; + +class FinderCallbackFunction : public MatchFinder::MatchCallback { +public : + QualType typeResult; + + virtual void run(const MatchFinder::MatchResult &Result) { + if (const FunctionDecl* decl = Result.Nodes.getNodeAs("function")) { + typeResult = decl->getType(); + } + } +}; + +void +ExternData::addLibrary(Atom&& name, Atom&& package) +{ + __dictLibraries.emplace(name.get(), package.get()); +} + +void +ExternData::addIncludeDecl(Expression&& e) +{ + assert(e.op == Operator::LIST_NAMED); + + //TODO implement Expression parsing(Array of Expr as vector); + int indexLib, indexHeaders; + for(size_t i=0, size=e.operands.size(); i headers; + std::transform(listHeaders.operands.begin(), listHeaders.operands.end(), std::inserter(headers, headers.end()), + [](const Expression& o){ + assert(o.__state == Expression::STRING); + return o.getValueString(); + }); + + entries.emplace_back(ExternEntry{package, std::move(headers)}); + } +} + +void +ExternLayer::addExternalData(const std::vector& data){ + entries.insert(entries.end(), data.begin(), data.end()); +} + +ExternLayer::ExternLayer(LLVMLayer *llvm): __llvm(llvm), __datalayout(llvm->module) +{} + + +std::vector +ExternLayer::fetchPackageFlags(const ExternEntry& entry){ + std::vector args; + FILE* flags = popen((string("pkg-config --cflags ") + entry.package).c_str(), "r"); + size_t linesize=0; + char* linebuf=0; + ssize_t linelen=0; + while ((linelen=getdelim(&linebuf, &linesize, ' ', flags))>0) { + if (linebuf[0]=='\n') continue; + if (linebuf[linelen-1 ] == ' ') + linebuf[linelen-1] = 0; + + llvm::outs() << '<' << linebuf << "> "; + args.push_back(linebuf); + + free(linebuf); + linebuf = 0; + } + pclose(flags); + return (args); +} + +std::vector +ExternLayer::fetchPackageLibs(const ExternEntry& entry){ + std::vector libs; + + FILE* flags = popen((string("pkg-config --libs ") + entry.package).c_str(), "r"); + size_t linesize=0; + char* linebuf=0; + ssize_t linelen=0; + while ((linelen=getdelim(&linebuf, &linesize, ' ', flags))>0) { + if (linebuf[0]=='\n') continue; + if (linebuf[linelen-1 ] == ' ') + linebuf[linelen-1] = 0; + + llvm::outs() << '<' << linebuf << "> "; + libs.push_back(linebuf); + + free(linebuf); + linebuf = 0; + } + pclose(flags); + return (libs); +} + +void +ExternLayer::loadLibraries(vector&& libs){ + string msgErr; + for (const string& lib: libs) { + if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently(lib.c_str(), &msgErr)){ + llvm::errs()<<"\n"<__externdata); + + QStringList code; + std::vector args{ + "-I/usr/local/include" + ,"-I/usr/lib/llvm-3.7/bin/../lib/clang/3.7.0/include" + ,"-I/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/include" + ,"-I/usr/include/x86_64-linux-gnu" + ,"-I/usr/include" + }; + + std::vector libs; + + for(const ExternEntry& entry: entries) + { + llvm::outs()<<"[ExternC] Processing package: "<< entry.package << "\n"; + llvm::outs()<<"[ExternC] args: "; + + vector&& args2 = fetchPackageFlags(entry); + args.insert(args.end(), args2.begin(), args2.end()); + for(const string arg: args2) { + llvm::outs()<< "<" << arg << "> "; + } + + llvm::outs()<<"\n[ExternC] libs: "; + args2 = fetchPackageLibs(entry); + for(const string arg: args2) { + llvm::outs()<< "<" << arg << "> "; + } + libs.insert(libs.end(), args2.begin(), args2.end()); + + + llvm::outs()<<"\n[ExternC] headers: "; + std::transform(entry.headers.begin(), entry.headers.end(), std::inserter(code, code.begin()), + [](const string header ) { + QString line = QString("#include \"%1\"").arg(header.c_str()); + llvm::outs()<< "<" << line.toStdString() << "> "; + + return line; + }); + + llvm::outs() << '\n'; + } + + + loadLibraries(move(libs)); + ast = buildASTFromCodeWithArgs(code.join('\n').toStdString(), args); + __cgo.reset(new CodeGenOptions); + __datalayout = llvm::DataLayout(ast->getASTContext().getTargetInfo().getTargetDescription()); + __cgm.reset(new CodeGen::CodeGenModule(ast->getASTContext(), *__cgo, *__llvm->module, __datalayout, ast->getASTContext().getDiagnostics())); +}; + + + +bool +ExternLayer::isPointer(const clang::QualType &t) { + const clang::Type * tInfo = t.getTypePtr(); + assert(tInfo); + + return tInfo->isAnyPointerType(); +} + +llvm::Type* +ExternLayer::toLLVMType(const clang::QualType& t){ + return __cgm->getTypes().ConvertType(t); +} + +std::vector +ExternLayer::getStructFields(const clang::QualType& ty) +{ + clang::QualType t = ty; + if (isPointer(ty)){ + const clang::PointerType* tPtr = ty->getAs(); + t = tPtr->getPointeeType(); + } + + assert(t.getTypePtr()->isRecordType()); + + const RecordType *record = t->getAsStructureType(); + assert(record); + + std::vector result; + //FieldDecl* field: record->getDecl()->fields() + for (auto i=record->getDecl()->field_begin(); i!= record->getDecl()->field_end(); ++i){ + result.push_back(i->getName()); + } + + return result; +} + +clang::QualType +ExternLayer::lookupType(const std::string& id){ + MatchFinder finder; + FinderCallbackTypeDecl callbackTypeDecl; + auto matcherTypeDecl = typedefDecl(hasName(id)).bind("typename"); + + finder.addMatcher(matcherTypeDecl, &callbackTypeDecl); + finder.matchAST(ast->getASTContext()); + + assert(! callbackTypeDecl.typeResult.isNull()); + return callbackTypeDecl.typeResult; +} + + +llvm::Function* +ExternLayer::lookupFunction(const std::string& name){ + if (__functions.count(name)){ + return __functions.at(name); + } + + MatchFinder finder; + FinderCallbackFunction callback; + auto matcher = functionDecl(hasName(name)).bind("function"); + + finder.addMatcher(matcher, &callback); + finder.matchAST(ast->getASTContext()); + + assert(! callback.typeResult.isNull()); + const QualType& tyFuncQual = callback.typeResult; + llvm::Type *tyRaw = __cgm->getTypes().ConvertType(tyFuncQual); + llvm::FunctionType* tyRawFunc = llvm::dyn_cast(tyRaw); + + llvm::Function* function = llvm::Function::Create(tyRawFunc, llvm::GlobalValue::ExternalLinkage, name, __llvm->module); + + __functions.emplace(name, function); + return function; +} diff --git a/cpp/src/ExternLayer.h b/cpp/src/ExternLayer.h new file mode 100644 index 0000000..cc2a18f --- /dev/null +++ b/cpp/src/ExternLayer.h @@ -0,0 +1,55 @@ +// +// Created by pgess on 4/21/15. +// + +#ifndef XREATE_EXTERNLAYER_H +#define XREATE_EXTERNLAYER_H + +#include "llvmlayer.h" +#include +#include +#include +#include "ast.h" +#include "clang/AST/ASTContext.h" +#include "/private/prg/vendors/clang/lib/CodeGen/CodeGenModule.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CodeGenOptions.h" + +namespace xreate { + struct ExternData { + void addLibrary(Atom&& name, Atom&& package); + void addIncludeDecl(Expression&& e); + + std::vector entries; + std::map __dictLibraries; + }; + + class ExternLayer { + public: + ExternLayer(LLVMLayer* llvm); + + llvm::Function* lookupFunction(const std::string& name); + clang::QualType lookupType(const std::string& id); + std::vector getStructFields(const clang::QualType& ty); + + llvm::Type* toLLVMType(const clang::QualType& t); + bool isPointer(const clang::QualType& t); + + void init(const AST* root); + static std::vector fetchPackageFlags(const ExternEntry& entry); + static std::vector fetchPackageLibs(const ExternEntry& entry); + private: + + std::unique_ptr ast; + std::unique_ptr __cgm; + std::unique_ptr __cgo; + llvm::DataLayout __datalayout; + LLVMLayer* __llvm; + std::vector entries; + std::map __functions; + + void addExternalData(const std::vector& data); + void loadLibraries(std::vector&& libs); + }; +} +#endif //XREATE_EXTERNLAYER_H diff --git a/cpp/src/ast-compilation.cpp b/cpp/src/ast-compilation.cpp deleted file mode 100644 index 1bf4c97..0000000 --- a/cpp/src/ast-compilation.cpp +++ /dev/null @@ -1,204 +0,0 @@ -#include -#include -#include "query/containers.h" -#include "instructions/instr-containers.h" - -using namespace xreate; -using namespace std; - - llvm::Value * - CodeScope::compileExpression(const Expression &expr, LLVMLayer &l, std::string hintRetVar) { - #define VARNAME(x) (hintRetVar.empty()? x: hintRetVar) - llvm::Value *left; - llvm::Value *right; - - - switch (expr.op) { - case Operator::ADD: - case Operator::SUB: - case Operator::MUL: - case Operator::DIV: - case Operator::EQU: - case Operator::LSS: - case Operator::GTR: - assert(expr.__state == Expression::COMPOUND); - assert(expr.operands.size() == 2); - - left = compileExpression(expr.operands[0], l); - right = compileExpression(expr.operands[1], l); - break; - - default:; - } - - switch (expr.op) { - case Operator::ADD: - return l.builder.CreateAdd(left, right, VARNAME("tmp_add")); - break; - - case Operator::SUB: - return l.builder.CreateSub(left, right, VARNAME("tmp_sub")); - break; - - case Operator::MUL: - return l.builder.CreateMul(left, right, VARNAME("tmp_mul")); - break; - - case Operator::DIV: - return l.builder.CreateSDiv(left, right, VARNAME("tmp_div")); - break; - - case Operator::EQU: - left->dump(); - right->dump(); - return l.builder.CreateICmpEQ(left, right, VARNAME("tmp_equ")); - break; - - case Operator::LSS: - return l.builder.CreateICmpSLT(left, right, VARNAME("tmp_lss")); - break; - - case Operator::GTR: - return l.builder.CreateICmpSGT(left, right, VARNAME("tmp_gtr")); - break; - - case Operator::NEG: - left = compileExpression(expr.operands[0], l); - return l.builder.CreateNeg(left, VARNAME("tmp_neg")); - break; - - case Operator::CALL: { - assert(expr.__state == Expression::COMPOUND); - - const std::string &fname = expr.__valueS; - - ManagedFnPtr calleeFunc = l.ast->findFunction(fname); - assert(calleeFunc.isValid()); - - llvm::Function *callee = calleeFunc->__raw; - - std::vector args; - args.reserve(expr.operands.size() - 1); - - std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), - [&l, this](const Expression &operand) { - return compileExpression(operand, l); - } - ); - - return l.builder.CreateCall(callee, args, VARNAME("tmp_call")); - } - - case Operator::LIST: - { - return containers::Instructions(this, &l).compileConstantArray(expr, VARNAME("list")); - }; - - case Operator::LIST_RANGE: - { - assert(false); //no compilation phase for a range list - // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); - }; - - - - case Operator::MAP: - { - assert(expr.blocks.size()); - return containers::Instructions(this, &l).compileMapArray(expr, VARNAME("map")); - }; - - case Operator::FOLD: - { - return containers::Instructions(this, &l).compileFold(expr, VARNAME("fold")); - }; - - case Operator::INDEX: - { - assert(expr.operands.size()); - const std::string &ident = expr.operands.begin()->getValueString(); - Symbol s = findSymbol(ident, l, true); - - std::vector indexes; - std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), - [this, &l] (const Expression& op){return compileExpression(op, l);} - ); - - return containers::Instructions(this, &l).compileIndex(s, indexes, VARNAME(string("el_") + ident)); - }; - - - case Operator::NONE: - assert(expr.__state != Expression::COMPOUND); - - switch (expr.__state) { - case Expression::IDENT: { - const std::string &vname = expr.__valueS; - const Symbol& var = findSymbol(vname, l, true); - return var.scope->__rawVars.at(var.identifier); - } - - case Expression::NUMBER: - int literal = expr.__valueD; - return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), literal); - }; - - break; - - } - - assert(false); - return 0; - } - - llvm::Value * - CodeScope::compile(LLVMLayer &l, const std::string& hintBlockName) { - if (!hintBlockName.empty()) { - llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockName, l.context.function); - l.builder.SetInsertPoint(block); - } - - return compileExpression(__body, l); - } - - llvm::Function * - Function::compile(LLVMLayer &l) { - std::vector types; - std::transform(__entry->__args.begin(), __entry->__args.end(), std::inserter(types, types.end()), - [this](const std::string &arg)->llvm::Type* { - assert(__entry->__vartable.count(arg)); - VID argid = __entry->__vartable.at(arg); - assert(__entry->__definitions.count(argid)); - return __entry->__definitions.at(argid).toLLVMType(); - }); - - llvm::FunctionType *ft = llvm::FunctionType::get(__entry->__definitions[0].toLLVMType(), types, false); - __raw = llvm::cast(l.module->getOrInsertFunction(__name, ft)); - - llvm::Function::arg_iterator fargsI = __raw->arg_begin(); - for (std::string &arg : __entry->__args) { - VID argid = __entry->__vartable[arg]; - - __entry->__rawVars[argid] = fargsI; - fargsI->setName(arg); - ++fargsI; - } - - l.context.function = __raw; - const std::string blockName = "entry"; - l.builder.CreateRet(__entry->compile(l, blockName)); - l.context.function = nullptr; - l.moveToGarbage(ft); - - return __raw; - }; - - void - AST::compile(LLVMLayer &layer) { - layer.ast = this; - layer.module = new llvm::Module(getModuleName(), llvm::getGlobalContext()); - - for (Function* f: __functions) { - llvm::Function *rawf = f->compile(layer); - } - } \ No newline at end of file diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 9051e77..6f7b723 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,456 +1,637 @@ #include "ast.h" +#include "ExternLayer.h" #include #include #include #include using namespace std; namespace xreate{ +class TypesResolver { +private: + const AST* ast; + std::map scope; + std::map signatures; + + + ExpandedType expandType(const TypeAnnotation &t, const std::vector &args = std::vector()){ + return TypesResolver(ast, scope, signatures)(t, args); + } + + std::vector + expandOperands(const std::vector& operands) { + std::vector pack; + + pack.reserve(operands.size()); + std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), + [this](const TypeAnnotation& t){ + return expandType(t); + }); + + return pack; + } + +public: + TypesResolver(const AST* root, const std::map& scopeOuter = std::map(), + std::map signaturesOuter = std::map()) + : ast(root), scope(scopeOuter), signatures(signaturesOuter) { + } + + + + ExpandedType + operator()(const TypeAnnotation &t, const std::vector &args = std::vector()) + { + assert(args.size() == t.bindings.size()); // invalid number of arguments + for (int i=0; i elTy = expandType(t.__operands.at(0)); + return ExpandedType(TypeAnnotation(tag_array, elTy, t.__size)); + } + + case TypeOperator::STRUCT: + { + assert(t.__operands.size()); + + std::vector&& pack = expandOperands(t.__operands); + auto tnew = TypeAnnotation(TypeOperator::STRUCT, move(pack)); + tnew.fields = t.fields; + + return ExpandedType(move(tnew)); + }; + + case TypeOperator::CALL: + { + std::string alias = t.__valueCustom; + + //find in local scope: + TypeAnnotation ty; + if (scope.count(alias)) { + ty = scope.at(alias); + + } else if (ast->__indexTypeAliases.count(alias)){ + ty = ast->__indexTypeAliases.at(alias); + + } else { + assert(false && "Undefined or external type"); + } + + std::vector&& operands = expandOperands(t.__operands); + TypeAnnotation signature(TypeOperator::CALL, move(operands)); + signature.__valueCustom = alias; + + if (signatures.count(signature)) { + auto link = TypeAnnotation(TypeOperator::LINK, {}); + link.conjuctionId = signatures.at(signature); + + return ExpandedType(move(link)); + } + + int cid = signatures.size(); + signatures[signature] = cid; + TypeAnnotation tyResult = expandType(ty, operands); + tyResult.conjuctionId = cid; + + return ExpandedType(move(tyResult)); + }; + + case TypeOperator::CUSTOM: + { + std::string alias = t.__valueCustom; + + /* + if (signatures.count(alias)) { + return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); + } + signatures[alias].emplace(t); + */ + + //find in local scope: + if (scope.count(alias)) + { + return expandType(scope.at(alias)); + } + + // find in general scope: + if(ast->__indexTypeAliases.count(alias)) { + return expandType(ast->__indexTypeAliases.at(t.__valueCustom)); + } + + //if type is unknown keep it as is. + return ExpandedType(TypeAnnotation(t)); + }; + + case TypeOperator::ACCESS: + { + std::string alias = t.__valueCustom; + ExpandedType tyAlias= ExpandedType(TypeAnnotation()); + + //find in local scope: + if (scope.count(alias)) { + tyAlias = expandType(scope.at(alias)); + + //find in global scope: + } else if((ast->__indexTypeAliases.count(alias))) { + tyAlias = expandType(ast->__indexTypeAliases.at(alias)); + + } else { + assert(false && "Undefined or external type"); + } + + assert(tyAlias->__operator == TypeOperator::STRUCT); + + for (const string& field: t.fields){ + auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field); + assert(fieldIt != tyAlias->fields.end() && "unknown field"); + + int fieldId = fieldIt - tyAlias->fields.begin(); + tyAlias = expandType(tyAlias->__operands.at(fieldId)); + } + + return tyAlias; + } + + case TypeOperator::TUPLE: { + assert(t.__operands.size()); + + std::vector pack; + pack.reserve(t.__operands.size()); + + std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack, pack.end()), + [this](const TypeAnnotation& t){ + return expandType(t); + }); + + return ExpandedType(TypeAnnotation(TypeOperator::TUPLE, move(pack))); + } + + case TypeOperator::NONE: { + return ExpandedType(TypeAnnotation(t)); + } + + default: + assert(false); + } + + assert(false); + return ExpandedType(TypeAnnotation()); + } +}; + TypeAnnotation::TypeAnnotation() { } TypeAnnotation::TypeAnnotation(const Atom &typ) : __value(typ.get()) { ; } TypeAnnotation::TypeAnnotation (TypePrimitive typ) : __value(typ) {} TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) : __operator(op), __operands(operands) { } -TypeAnnotation::TypeAnnotation (llvm_array_tag, TypePrimitive typ, int size) - :TypeAnnotation(TypeOperator::LIST, {typ}) -{ - __size=size; -} -/* -TypeAnnotation (struct_tag, std::initializer_list) +TypeAnnotation::TypeAnnotation (TypeOperator op, std::vector&& operands) + : __operator(op), __operands(operands) {} -*/ -llvm::Type* -TypeAnnotation::toLLVMType() + +TypeAnnotation::TypeAnnotation (llvm_array_tag, TypeAnnotation typ, int size) + :TypeAnnotation(TypeOperator::ARRAY, {typ}) { - switch (__operator) - { - case TypeOperator::LIST: - { - assert(__operands.size()); - TypeAnnotation elTy = __operands.at(0); + __size=size; +} - return llvm::ArrayType::get(elTy.toLLVMType(), __size); - } +bool +TypeAnnotation::operator< (const TypeAnnotation& t) const{ + if (__operator != t.__operator) return __operator < t.__operator; - case TypeOperator::NONE: { - switch (__value) { - case TypePrimitive::Bool: - return llvm::Type::getInt1Ty(llvm::getGlobalContext()); + if (__operator == TypeOperator::NONE) + return __value < t.__value; - case TypePrimitive::Int: - case TypePrimitive::i32: - case TypePrimitive::Num: - return llvm::Type::getInt32Ty(llvm::getGlobalContext()); + if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS){ + if (__valueCustom != t.__valueCustom) + return __valueCustom < t.__valueCustom; + } - case TypePrimitive::Float: - return llvm::Type::getDoubleTy(llvm::getGlobalContext()); + return __operands < t.__operands; +} - default: - assert(false); - } - } +/* +TypeAnnotation (struct_tag, std::initializer_list) +{} +*/ - default: - assert(false); - } +void +TypeAnnotation::addBindings(std::vector>&& params) +{ + bindings.reserve(params.size()); - assert(false); - return nullptr; + std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), + [](const Atom& ident){return ident.get(); }); } - - Expression::Expression(const Atom& number) : __state(NUMBER), op(Operator::NONE), __valueD(number.get()) { } +Expression::Expression(const Atom& a) + : __state(STRING), op(Operator::NONE), __valueS(a.get()) +{ +} + Expression::Expression(const Atom &ident) : __state(IDENT), op(Operator::NONE), __valueS(ident.get()) { + + if (ident.get() == "null") { + __state = NONE; + } } Expression::Expression(const Operator &oprt, std::initializer_list params) : __state(COMPOUND), op(oprt) { if (op == Operator::CALL) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); + + operands.insert(operands.end(), params.begin()+1, params.end()); return; } - operands.insert(operands.end(), params); + operands.insert(operands.end(), params.begin(), params.end()); } void Expression::setOp(Operator oprt) { op = oprt; switch (op) { case Operator::NONE: __state = INVALID; break; default: __state = COMPOUND; break; } } void Expression::addArg(Expression &&arg) { operands.push_back(arg); } void Expression::addBindings(std::initializer_list> params) { - std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), - [] (const Atom atom){ - return atom.get(); - }); + addBindings(params.begin(), params.end()); +} + +void +Expression::bindType(TypeAnnotation&& t) +{ + type = t; } void Expression::addBlock(ManagedScpPtr scope) { - blocks.push_back(scope); + blocks.push_back(scope.operator ->()); } const std::vector& Expression::getOperands() const { return operands; } double Expression::getValueDouble() const { return __valueD; } const std::string& Expression::getValueString() const { return __valueS; } +void +Expression::setValue(const Atom&& v){ + __valueS = v.get(); +} +bool +Expression::isNone() const{ + return (op == Operator::NONE && __state == NONE); +} +bool +Expression::isValid() const{ + return (__state != INVALID); +} Expression::Expression() : op(Operator::NONE), __state(INVALID) {} AST::AST() { } void AST::addDFAData(Expression &&data) { __dfadata.push_back(data); } +void +AST::addExternData(ExternData &&data) { + __externdata.insert(__externdata.end(), data.entries.begin(), data.entries.end()); +} + void AST::add(Function* f) { __functions.push_back(f); __indexFunctions[f->getName()] = __functions.size()-1; } void AST::add(MetaRuleAbstract *r) { __rules.push_back(r); } +void +AST::add(TypeAnnotation&& t, Atom&& alias){ + __indexTypeAliases.emplace(alias.get(), t); +} + ManagedScpPtr AST::add(CodeScope* scope) { this->__scopes.push_back(scope); return ManagedScpPtr(this->__scopes.size()-1, &this->__scopes); } std::string AST::getModuleName() { const std::string name = "moduleTest"; return name; } ManagedPtr AST::findFunction(const std::string& name) { - assert (__indexFunctions.count(name)); + if (! __indexFunctions.count(name)) { + return ManagedFnPtr::Invalid(); + } return ManagedPtr(__indexFunctions.at(name), &__functions); } -void -AST::run(LLVMLayer &l) + template<> +ManagedPtr +AST::begin() +{return ManagedPtr(0, &this->__functions);} + +template<> +ManagedPtr +AST::begin() +{return ManagedPtr(0, &this->__scopes);} + +template<> +ManagedPtr +AST::begin() +{return ManagedPtr(0, &this->__rules);} + + +Expanded +AST::expandType(const TypeAnnotation &t) const { - llvm::PassManager PM; - PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner")); - PM.run(*l.module); + return TypesResolver(this)(t); } - template<> - ManagedPtr - AST::begin() - {return ManagedPtr(0, &this->__functions);} +Expanded +AST::findType(const std::string& name){ + // find in general scope: + if(__indexTypeAliases.count(name)) + return expandType(__indexTypeAliases.at(name)); - template<> - ManagedPtr - AST::begin() - {return ManagedPtr(0, &this->__scopes);} - - template<> - ManagedPtr - AST::begin() - {return ManagedPtr(0, &this->__rules);} + //if type is unknown keep it as is. + TypeAnnotation t(TypeOperator::CUSTOM, {}); + t.__valueCustom = name; + return ExpandedType(move(t)); +} Function::Function(const Atom& name) : __entry(new CodeScope(0)) { __name = name.get(); } void Function::addTag(Expression&& tag, const TagModifier mod) { __tags.emplace_back(tag, mod); } const std::vector& Function::getAnnotations() const { return __tags; } CodeScope* Function::getEntryScope() const { return __entry; } void CodeScope::addArg(Atom && name, TypeAnnotation&& typ) { VID id = registerVar(std::move(const_cast(name.get())), std::move(typ)); __args.push_back(name.get()); } ; void Function::addArg(Atom && name, TypeAnnotation&& typ) { __entry->addArg(move(name), move(typ)); } void Function::setReturnType(const TypeAnnotation &rtyp) { __entry->__definitions[0] = rtyp; } const std::string& Function::getName() const { return __name; } CodeScope::CodeScope(CodeScope* parent) :__parent(parent) {} CodeScope::~CodeScope() {} VID CodeScope::registerVar(std::string&& name, TypeAnnotation &&typ) { __vartable[name] = ++__vCounter; __definitions[__vCounter] = typ; return __vCounter; } -void -CodeScope::bindArg(llvm::Value* var, std::string&& name) -{ - assert(__vartable.count(name)); - VID id = __vartable.at(name); - __rawVars[id] = var; -} - void CodeScope::addDeclaration(const Atom &&name, TypeAnnotation &&typ, Expression&& body) { VID id = registerVar(std::move(const_cast(name.get())), move(typ)); __declarations[id] = body; } void CodeScope::setBody(const Expression &body) { __body = body; } TypeAnnotation& CodeScope::findDefinition(const Symbol& symbol) { CodeScope* self = symbol.scope; - self->__definitions[symbol.identifier]; + assert(self->__definitions.count(symbol.identifier)); + return self->__definitions[symbol.identifier]; } Symbol -CodeScope::findSymbol(const std::string &name, LLVMLayer &l, bool forceCompile) +CodeScope::findSymbol(const std::string &name) { //search var in current block if (__vartable.count(name)) { VID vId = __vartable.at(name); Symbol result{vId, this}; - - if (!forceCompile) - { - return result; - } - - //search in already compiled vars - if (__rawVars.count(vId)) - { - return result; - } - - if (!__declarations.count(vId)) { - //error: symbol is uncompiled scope arg - assert(false); - } - - const Expression& e = __declarations.at(vId); - - __rawVars[vId] = compileExpression(e, l, name); return result; } //search in parent scope if (__parent) { - return __parent->findSymbol(name, l); + return __parent->findSymbol(name); } //exception: Ident not found assert(false); } + + bool CodeScope:: hasDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; return (self->__declarations.count(symbol.identifier)); } -llvm::Value* -CodeScope::compileExpression(const Symbol& s, LLVMLayer& l, std::string hintRetVar) -{ - CodeScope* self = s.scope; - - if (self->__rawVars.count(s.identifier)) - { - return self->__rawVars[s.identifier]; - } - - return self->__rawVars[s.identifier] = self->compileExpression(findDeclaration(s), l, hintRetVar); -} - const Expression& CodeScope::findDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; if (! self->__declarations.count(symbol.identifier)) { // no declaration exists assert(false); } return self->__declarations[symbol.identifier]; } void RuleArguments::add(const Atom &arg, DomainAnnotation typ) { emplace_back(arg.get(), typ); } void RuleGuards::add(Expression&& e) { push_back(e); } MetaRuleAbstract:: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) : __args(std::move(args)), __guards(std::move(guards)) {} MetaRuleAbstract::~MetaRuleAbstract(){} RuleWarning:: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) : MetaRuleAbstract(std::move(args), std::move(guards)), __condition(condition), __message(message.get()) {} RuleWarning::~RuleWarning(){} void RuleWarning::compile(ClaspLayer& layer) { layer.addRuleWarning(*this); } bool operator< (const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope==s2.scope && s1.identifier #include #include -#include "llvmlayer.h" #include #include #include #include #include "attachments.h" +#include "utils.h" +#include + +namespace llvm{ + class Value; +} namespace xreate { struct String_t{}; struct Identifier_t {}; struct Number_t {}; struct Type_t {}; template class Atom {}; template<> class Atom { public: Atom(const std::wstring& value) { char buffer[32]; wcstombs(buffer, value.c_str(), 32); __value = buffer; } Atom(std::string && name): __value(name) {} const std::string& get() const{return __value; } private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value) { __value = wcstol(value, 0, 10); } Atom(int value) : __value(value) {} double get()const {return __value; } private: double __value; }; template<> class Atom { public: Atom(const std::wstring& value) : __value(++value.begin(), --value.end()) {} const std::string& get() const {return __value; } private: std::string __value; }; -enum class TypePrimitive {Bool, Int, Float, Num, String, i32}; +enum class TypePrimitive {Bool, Int, Float, Num, String, I32, I8}; template<> class Atom { public: Atom(wchar_t* value) { char buffer_[32]; wcstombs(buffer_, value, 32); std::string buffer(buffer_); if (buffer=="bool"){ __value = TypePrimitive ::Bool; } else if (buffer=="int") { __value = TypePrimitive::Int; } else if (buffer=="float") { __value = TypePrimitive::Float; } else if (buffer=="num") { __value = TypePrimitive::Num; } else if (buffer=="string") { __value = TypePrimitive::String; } } Atom() { } TypePrimitive get() const { return __value; } private: TypePrimitive __value; }; typedef Atom TypeAtom; -enum class TypeOperator{NONE, LIST, STRUCT}; +enum class TypeOperator{NONE, CALL, CUSTOM, ARRAY, TUPLE, STRUCT, ACCESS, LINK}; struct llvm_array_tag {}; struct struct_tag{}; const llvm_array_tag tag_array = llvm_array_tag(); const struct_tag tag_struct = struct_tag(); class TypeAnnotation { public: TypeAnnotation(); TypeAnnotation (const Atom& typ); TypeAnnotation (TypePrimitive typ); - TypeAnnotation (llvm_array_tag, TypePrimitive typ, int size); + TypeAnnotation (llvm_array_tag, TypeAnnotation typ, int size); TypeAnnotation (TypeOperator op, std::initializer_list operands); + TypeAnnotation (TypeOperator op, std::vector&& operands); + void addBindings(std::vector>&& params); + bool operator< (const TypeAnnotation& t) const; // TypeAnnotation (struct_tag, std::initializer_list); - llvm::Type* toLLVMType(); - TypePrimitive __value; TypeOperator __operator = TypeOperator::NONE; + std::vector __operands; - int __size = 0; -private: + TypePrimitive __value; + std::string __valueCustom; + int conjuctionId=-1; //conjunction point id (relevant for recursive types) + uint64_t __size = 0; + std::vector fields; + std::vector bindings; +private: }; enum class Operator { -ADD, SUB, MUL, DIV, EQU, LSS, GTR, NEG, LIST, LIST_RANGE, CALL, NONE, IMPL/* implication */, MAP, FOLD, INDEX, IF +ADD, SUB, MUL, DIV, EQU, LSS, GTR, NEG, LIST, LIST_RANGE, LIST_NAMED, CALL, NONE, IMPL/* implication */, MAP, FOLD, INDEX, IF }; class Function; class AST; class CodeScope; class MetaRuleAbstract; template struct ManagedPtr { - ManagedPtr(){}; + static ManagedPtr Invalid(){ + return ManagedPtr(); + } + + ManagedPtr(): __storage(0) {} ManagedPtr(unsigned int id, const std::vector* storage) : __id(id), __storage(storage) {} Target& operator*() const { - return *(*__storage).at(__id); + assert(isValid() && "Invalid Ptr"); + return *__storage->at(__id); } void operator=(const ManagedPtr& other) { __id = other.__id; __storage = other.__storage; } bool operator == (const ManagedPtr& other) { return isValid() && (__id == other.__id); } Target* operator->() const noexcept { - assert(isValid()); + assert(isValid() && "Invalid Ptr"); return __storage->at(__id); } inline bool isValid() const { return (__storage) && (0 <= __id) && (__id < __storage->size()); } + inline operator bool() const { + return isValid(); + } + ManagedPtr& operator++() { ++__id; return *this; } inline unsigned int id() { return __id; } private: unsigned int __id =0; const std::vector * __storage=0; }; typedef ManagedPtr ManagedFnPtr; typedef ManagedPtr ManagedScpPtr; typedef ManagedPtr ManagedRulePtr; const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); struct Expression { friend class CodeScope; friend class ClaspLayer; friend class CFGPass; Expression(const Operator &oprt, std::initializer_list params); Expression(const Atom& ident); Expression(const Atom& number); + Expression(const Atom& a); Expression(); void setOp(Operator oprt); void addArg(Expression&& arg); void addBindings(std::initializer_list> params); + void bindType(TypeAnnotation&& t); + + template + void addBindings(InputIt paramsBegin, InputIt paramsEnd); + void addBlock(ManagedScpPtr scope); const std::vector& getOperands() const; double getValueDouble() const; const std::string& getValueString() const; + void setValue(const Atom&& v); + bool isNone() const; + bool isValid() const; Operator op; - enum {INVALID, COMPOUND, IDENT, NUMBER, STRING} __state; + enum {INVALID, COMPOUND, IDENT, NUMBER, STRING, NONE} __state = INVALID; std::vector bindings; - std::list blocks; + std::map __indexBindings; std::vector operands; + TypeAnnotation type; + + std::map tags; + std::list blocks; private: std::string __valueS; double __valueD; + + }; +template +void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { + size_t index = bindings.size(); + + std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), + [&index, this] (const Atom atom){ + std::string key = atom.get(); + this->__indexBindings[key] = index++; + return key; + }); +} + typedef std::list ExpressionList; enum class TagModifier {NONE, ASSERT, REQUIRE}; enum class DomainAnnotation {FUNCTION, VARIABLE}; class RuleArguments: public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards: public std::vector { public: void add(Expression&& e); }; class ClaspLayer; class LLVMLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); virtual void compile(ClaspLayer& layer) =0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning: public MetaRuleAbstract { friend class ClaspLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); virtual void compile(ClaspLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VID; /* class Expression: ExpressionAbstract { friend class CFGPass; public: llvm::Value* compile(LLVMLayer& l, Function* f, std::string* hintRetVar=0) const; }; */ typedef std::pair VariableDefinition; typedef std::pair VariableDeclaration; typedef std::pair Tag; struct Symbol { VID identifier; CodeScope * scope; }; +struct SymbolTags_t{}; + +template<> +struct AttachmentsDict { + typedef std::map Data; + static const unsigned int key = 2; +}; + bool operator< (const Symbol& s1, const Symbol& s2); bool operator== (const Symbol& s1, const Symbol& s2); class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent=0); void setBody(const Expression& body); void addDeclaration(const Atom &&name, TypeAnnotation &&typ, Expression&& body); void addArg(Atom && name, TypeAnnotation&& typ); - void bindArg(llvm::Value* var, std::string&& name); + //TODO exclude forceCompile partz - Symbol findSymbol(const std::string &name, LLVMLayer &l, bool forceCompile=false); + Symbol findSymbol(const std::string &name); static const Expression& findDeclaration(const Symbol& symbol); static TypeAnnotation& findDefinition(const Symbol& symbol); static bool hasDeclaration(const Symbol& symbol); - static llvm::Value* compileExpression(const Symbol& s, LLVMLayer& l, std::string hintRetVar=""); - llvm::Value* compile(LLVMLayer &l, const std::string & hintBlockName=""); - ~CodeScope(); std::vector __args; Expression __body; //TODO move __body to __declarations[0] - std::map __rawVars; - virtual llvm::Value* compileExpression(const Expression& expr, LLVMLayer& l, std::string hintRetVar=""); + SymbolAttachments attachments; -protected: + std::map __vartable; /** - * definition of return type have variable index Zero(0) + * definition of return type has variable index Zero(0) */ //TODO move __definitions to SymbolsAttachments data std::unordered_map __definitions; std::unordered_map __declarations; - std::map __vartable; +protected: + + VID __vCounter=1; CodeScope* __parent; std::list __storage; VID registerVar(std::string&& name, TypeAnnotation &&typ); - }; class Function { friend class Expression; friend class CodeScope; friend class AST; public: Function(const Atom& name); void addArg(Atom && name, TypeAnnotation&& typ); void addTag(Expression&& tag, const TagModifier mod); void setReturnType(const TypeAnnotation& rtyp); const std::string& getName() const; - - llvm::Function* compile(LLVMLayer& l); const std::vector& getAnnotations() const; CodeScope* getEntryScope() const; -private: - CodeScope* __entry; std::string __name; +private: + std::vector __tags; +}; - llvm::Function* __raw; -}; +class ExternData; +struct ExternEntry { + std::string package; + std::vector headers; +}; +typedef Expanded ExpandedType; class AST { public: AST(); + + /** + * DFA Interface + */ + void addDFAData(Expression&& data); + + /** + * Extern Interface + */ + void addExternData(ExternData&& data); + void add(Function* f); void add(MetaRuleAbstract* r); - void addDFAData(Expression&& data); ManagedScpPtr add(CodeScope* scope); - void compile(LLVMLayer& l); - void run(LLVMLayer& l); - std::string getModuleName(); - ManagedPtr findFunction(const std::string& name); + template ManagedPtr begin(); + std::vector __externdata; std::list __dfadata; //TODO move to more appropriate place std::list __rawImports; //TODO move to more appropriate place + private: std::vector __rules; std::vector __functions; std::vector __scopes; - std::map __indexFunctions; + + + // ***** TYPES SECTION ***** + public: +std::map __indexTypeAliases; +ExpandedType expandType(const TypeAnnotation &t) const; +ExpandedType findType(const std::string& name); +void add(TypeAnnotation&& t, Atom&& alias); + + private: +ExpandedType expandType(const TypeAnnotation &t, std::map scope, + const std::vector &args = std::vector()) const; + + // ***** TYPES SECTION END ***** }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); + } #endif // AST_H diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h index 1b79036..08b8579 100644 --- a/cpp/src/attachments.h +++ b/cpp/src/attachments.h @@ -1,109 +1,143 @@ // // Created by pgess on 3/15/15. // #ifndef _XREATE_ATTACHMENTS_H_ #define _XREATE_ATTACHMENTS_H_ #include +#include +#include namespace xreate { //Attachemnt Tags: struct IsDeclVisited{}; + struct IsImplementationOnTheFly{}; //Atachments dictionary template - struct AttachmentsDictionary + struct AttachmentsDict { // typedef void Data; }; template<> - struct AttachmentsDictionary + struct AttachmentsDict { typedef bool Data; static const unsigned int key = 0; }; + template<> + struct AttachmentsDict + { + typedef bool Data; + static const unsigned int key = 3; + }; + class Symbol; typedef unsigned int VID; class AttachmentsImpl { friend class SymbolAttachments; }; //TODO copy function to copy whole data from symbol to symbol: copy(sTo, sFrom); class SymbolAttachments { public: //TODO add specialization for pointers template - static void put(const Symbol& symbol, typename AttachmentsDictionary::Data && data) + using Data = typename AttachmentsDict::Data; + + template + using Input = typename std::conditional>::value, Data, Data&&>::type; + + template + static typename std::enable_if>::value>::type + put(const Symbol& symbol, Input data) { - typedef typename AttachmentsDictionary::Data Typ; - const unsigned int key = AttachmentsDictionary::key; - Typ* ptr = new Typ(data); + const unsigned int key = AttachmentsDict::key; + put(symbol, key, (void*) data); + } - put(symbol, key, ptr); + template + static typename std::enable_if>::value>::type + put(const Symbol& symbol, Input data) + { + const unsigned int key = AttachmentsDict::key; + Data* holder = new Data(data); + put(symbol, key, (void*) holder); } /* template using Tag2 = std::enable_if, Tag>:: - static void put(const Symbol& symbol, typename AttachmentsDictionary::Data && data) + static void put(const Symbol& symbol, typename AttachmentsDict::Data && data) { - typedef typename AttachmentsDictionary::Data Typ; + typedef typename AttachmentsDict::Data Typ; Typ* ptr = new Typ(data); AttachmentsImpl::put(symbol, ptr); } */ template - static typename AttachmentsDictionary::Data& get(const Symbol& symbol, typename AttachmentsDictionary::Data&& valueDefault) + static typename AttachmentsDict::Data& get(const Symbol& symbol, typename AttachmentsDict::Data&& valueDefault) { - typedef typename AttachmentsDictionary::Data Typ; - const unsigned int key = AttachmentsDictionary::key; + typedef typename AttachmentsDict::Data Typ; + const unsigned int key = AttachmentsDict::key; Typ* def = new Typ(valueDefault); Typ* result = static_cast (get(symbol, key, def)); - if (result != def) delete def; + if (result != def) delete def; //TODO check is there some mem leaks? return *result; } template - static typename AttachmentsDictionary::Data& get(const Symbol& symbol) + static typename std::enable_if>::value, Data>::type + get(const Symbol& symbol) + { + const unsigned int key = AttachmentsDict::key; + Data result = reinterpret_cast> (get(symbol, key, nullptr)); + + assert(result != nullptr); // data not found for the symbol + return result; + } + + template + static typename std::enable_if>::value, Data&>::type + get(const Symbol& symbol) { - typedef typename AttachmentsDictionary::Data Typ; - const unsigned int key = AttachmentsDictionary::key; + const unsigned int key = AttachmentsDict::key; - Typ* result = static_cast (get(symbol, key, nullptr)); + Data* result = reinterpret_cast*> (get(symbol, key, nullptr)); assert(result != nullptr); // data not found for the symbol return *result; } template static bool exists(const Symbol& symbol) { - const unsigned int key = AttachmentsDictionary::key; + const unsigned int key = AttachmentsDict::key; return exists(symbol, key); } private: typedef std::map Attachment; std::map __data; static void put(const Symbol& symbol, unsigned int key, void* data); static void* get(const Symbol& symbol, unsigned int key, void *def); static bool exists(const Symbol& symbol, unsigned int key); }; } #endif //_XREATE_ATTACHMENTS_H_ diff --git a/cpp/src/clasplayer.cpp b/cpp/src/clasplayer.cpp index b9707e8..34a7708 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/clasplayer.cpp @@ -1,466 +1,482 @@ #include "clasplayer.h" #include // for defining logic programs #include // unfounded set checkers #include // for enumerating answer sets #include #include #include #include +#include "utils.h" using namespace std; namespace xreate { void ClaspLayer::printWarnings(std::ostream& out) { const std::string warningTag = "warning"; auto warningsRange = __model.equal_range(warningTag); for (auto warning=warningsRange.first; warning!= warningsRange.second; ++warning) { unsigned int warningId; Gringo::Value params; std::tie(warningId, params) = parse(warning->second); cout << "Warning: " << __warnings.at(warningId) << " "; params.print(out); out< warnings; cout << "Model: " << endl; + + const string& atomBindVar = Config::get("clasp.bindings.variable"); + const string& atomBindFunc = Config::get("clasp.bindings.function"); + for (Gringo::Value atom : model.atoms(Gringo::Model::ATOMS)) { atom.print(cout); - cout << endl; + cout <<" | "<< endl; + + if (*atom.name() == atomBindVar || *atom.name() == atomBindFunc){ + string name = *std::get<1>(parse(atom)).name(); + __model.emplace(move(name), move(atom)); + continue; + } __model.emplace(*atom.name(), move(atom)); } + + return true; } QStringList multiplyLists(std::list &&lists) { QStringList result = lists.front(); lists.pop_front(); for (QStringList &list: lists) { QStringList::const_iterator end = result.end(); for (QStringList::iterator expr1I = result.begin(); expr1I < end; ++expr1I) { if (list.size() == 0) continue; QStringList::const_iterator expr2I = list.begin(); for (int expr2No = 0, size = list.size() - 1; expr2No < size; ++expr2No, ++expr1I) result.append(QString("%1, %2").arg(*expr1I).arg(*expr2I)); *expr1I = QString("%1, %2").arg(*expr1I).arg(*expr2I); } } return result; } void ClaspLayer::addCFAData(CFGraph &&graph) { ostream &cout = __partGeneral; cout << endl << "%\t\tStatic analysis: CFA" << endl; for (const std::pair &relation: graph.__relations) { const string &tagFrom = graph.__nodes.at(relation.first); const string &tagTo = graph.__nodes.at(relation.second); cout << (QString("call(%1, %2) .").arg(tagFrom.c_str()).arg(tagTo.c_str())).toStdString() << endl; } } void - ClaspLayer::addDFAData(DFGraph &&graph) + ClaspLayer::addDFAData(DFAGraph &&graph) { - dfgData = graph; + dfaData = graph; std::set symbols; ostream &cout = __partGeneral; cout << endl << "%\t\tStatic analysis: DFA" << endl; std::vector>::iterator i1; std::vector::iterator i2; - for (i1=dfgData.__edges.begin(), i2 = dfgData.__data.begin(); i1!= dfgData.__edges.end(); ++i1, ++i2 ) + for (i1= dfaData.__edges.begin(), i2 = dfaData.__data.begin(); i1!= dfaData.__edges.end(); ++i1, ++i2 ) { QString edgeData; switch (*i2) { case DFGConnection::OPT: edgeData = "opt"; break; - case DFGConnection::STRONG: edgeData = "strong"; break; + case DFGConnection::ALIAS: edgeData = "alias"; break; case DFGConnection::PROTO: edgeData = "proto"; break; } cout << QString("dfa_connection(%1, %2, %3).") .arg(QString("(%1, %2)").arg(i1->first.identifier).arg(i1->first.scope)) .arg(QString("(%1, %2)").arg(i1->second.identifier).arg(i1->second.scope)) .arg(edgeData).toStdString() << endl; symbols.insert(i1->first); symbols.insert(i1->second); } - for (const pair& tag: dfgData.__tags) + for (const pair& tag: dfaData.__tags) { for (QString variant: compile(tag.second)) { cout << QString("bind(%1, %2).") .arg(QString("(%1, %2)").arg(tag.first.identifier).arg(tag.first.scope)) .arg(variant).toStdString()< &tags) { ostream &cout = __partTags; cout << (QString("function(%1) .").arg(function.c_str())).toStdString() << std::endl; int tagsCount = 0; for (const Tag &tag: tags) { QStringList tagRaw = compile(tag.first); assert(tagRaw.size() == 1); - cout << QString("tag(%1, %2).").arg(function.c_str()).arg(tagRaw.at(0)).toStdString() << endl; + std::string atom_binding = Config::get("clasp.bindings.function"); + cout << QString("%1(%2, %3).").arg(atom_binding.c_str()).arg(function.c_str()).arg(tagRaw.at(0)).toStdString() << endl; ++tagsCount; } + if (tagsCount == 0) { cout << "%no tags at all" << endl; } } void ClaspLayer::addRuleWarning(const RuleWarning &rule) { //__partGeneral << rule << endl; QStringList domains; std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()), [](const std::pair &argument) { string domain; switch (argument.second) { case DomainAnnotation::FUNCTION: domain = "function"; break; case DomainAnnotation::VARIABLE: domain = "variable"; break; } return QString("%1(%2)").arg(domain.c_str()).arg(argument.first.c_str()); }); QStringList vars; std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), [](const std::pair &argument) { return argument.first.c_str(); }); std::list guardsRaw; std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), [this](const Expression &guard) { return compile(guard); }); QStringList guards = multiplyLists(std::move(guardsRaw)); QStringList &&branches = compileNeg(rule.__condition); for (const QString &guardsJoined: guards) for (const QString &branch: branches) { unsigned int hook = registerWarning(string(rule.__message)); QString result = QString("warning(%1, (%2)):- %3, %4, %5.") .arg(hook) .arg(vars.join(", ")) .arg(branch) .arg(guardsJoined) .arg(domains.join(", ")); __partGeneral << result.toStdString() << endl; } } QStringList ClaspLayer::compile(const Expression &e) const { QStringList result; switch (e.op) { case Operator::CALL: { assert(e.__state == Expression::COMPOUND); std::list operands; std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), [this](const Expression &e) { return compile(e); }); QStringList &&operands_ = multiplyLists(std::move(operands)); result.append(QString("%1(%2)").arg(e.__valueS.c_str()).arg(operands_.join(", "))); break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); QStringList &&rawOp = compile(op); assert(rawOp.size() == 1); result.append(QString("not %1").arg(rawOp.at(0))); break; }; case Operator::NONE: { switch (e.__state) { case Expression::IDENT: result.append(QString(e.__valueS.c_str())); break; case Expression::NUMBER: result.append(QString::number(e.__valueD)); break; default: assert(true); } break; } } return result; } QStringList ClaspLayer::compileNeg(const Expression &e) const { QStringList result; switch (e.op) { case Operator::IMPL: { assert(e.__state == Expression::COMPOUND); assert(e.operands.size() == 2); QStringList operands1 = compile(e.operands.at(0)); QStringList operands2 = compile(e.operands.at(1)); for (const auto &op1: operands1) for (const auto &op2: operands2) { result.append(QString("%1, not %2").arg(op1).arg(op2)); } break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); QStringList &&rawOp = compile(op); assert(rawOp.size() == 1); result.append(rawOp.at(0)); break; }; default: assert(true); } return result; } unsigned int ClaspLayer::registerWarning(std::string &&message) { static int warningId = 0; __warnings.emplace(warningId, message); return warningId++;; } void ClaspLayer::addImports() { ostream &out = __partGeneral; for (string fn: ast->__rawImports) { std::ifstream file(fn); if (!file) continue; while(!file.eof()){ string line; std::getline(file, line); out << line << endl; } } } void ClaspLayer::run() { addImports(); ostringstream program; program << __partTags.str() << __partGeneral.str(); - cout << program.str() << endl; + cout << FYEL(program.str()) << endl; const char *argv[] = {nullptr, nullptr}; ClingoLib ctl(2, argv); //prg.add("p", ["t"], "q(t).") Gringo::FWStringVec vars{}; ctl.add("base", vars, program.str()); //prg.ground([("p", [2])]) Gringo::Control::GroundVec vals{std::make_pair("base", Gringo::FWValVec {})}; ctl.ground(vals, Gringo::Any()); //solve Gringo::Control::Assumptions as; Gringo::SolveResult result = ctl.solve(Gringo::Control::ModelHandler([&](Gringo::Model const &model) { return this->onModel(model); }), std::move(as)); if (result == Gringo::SolveResult::SAT) { - cout << "SUCCESSFULLY" << endl; + cout << FGRN("SUCCESSFULLY") << endl; } else { - cout << "UNSUCCESSFULLY" << endl; + cout << FRED("UNSUCCESSFULLY") << endl; } // invoke all query plugins to process clasp data for (IQuery* q: __queries) { q->init(this); } } ClaspLayer::ClaspLayer() { } - std::pair + ClaspLayer::ModelRange ClaspLayer::query(const std::string& atom) { - return __model.equal_range(atom); + if (! __model.count(atom)){ + return boost::none; + } + + return ModelRange(__model.equal_range(atom)); + } + + SymbolPacked + ClaspLayer::pack(const Symbol& symbol, std::string hintSymbolName) + { + auto pos = __indexScopes.emplace(symbol.scope, __indexScopes.size()); + if (pos.second) + __registryScopes.push_back(symbol.scope); + + SymbolPacked result; + result.scope = pos.first->second; + result.identifier = symbol.identifier; + + return result; } + Symbol + ClaspLayer::unpack(const SymbolPacked& symbol) + { + return Symbol{symbol.identifier, __registryScopes[symbol.scope]}; + }; + /* void AspOutPrinter::reportSolution(const Clasp::Solver&, const Clasp::Enumerator&, bool complete) { if (complete) std::cout << "No more models!" << std::endl; else std::cout << "More models possible!" << std::endl; } void AspOutPrinter::reportModel(const Clasp::Solver& s, const Clasp::Enumerator&) { std::cout << "Model " << s.stats.solve.models << ": \n"; // get the symbol table from the solver const Clasp::AtomIndex& symTab = *s.strategies().symTab; for (Clasp::AtomIndex::const_iterator it = symTab.begin(); it != symTab.end(); ++it) { // print each named atom that is true w.r.t the current assignment } std::cout << std::endl; } */ /***************************************** * CFGraph ***************************************** */ void CFGraph::addNode(unsigned int function, std::string &&tag) { __nodes.emplace(function, tag); } bool CFGraph::existsNode(unsigned int function) const { return __nodes.count(function); } void CFGraph::addLink(unsigned int nodeFrom, unsigned int nodeTo) { __relations.insert(std::make_pair(nodeFrom, nodeTo)); } /***************************************** - * DFGraph + * DFAGraph ***************************************** */ bool - DFGraph::linkExists(const SymbolPacked& node1, const SymbolPacked& node2) + DFAGraph::linkExists(const SymbolPacked& node1, const SymbolPacked& node2) { auto range = __outEdges.equal_range(node2); for(std::multimap::iterator edge = range.first; edge != range.second; ++edge) { if (__edges[edge->second].second == node1) return true; } return false; } void - DFGraph::addLink(const SymbolPacked& nodeTo, const SymbolPacked& nodeFrom, DFGConnection link) { + DFAGraph::addLink(const SymbolPacked& nodeTo, const SymbolPacked& nodeFrom, DFGConnection link) { if (!linkExists(nodeTo, nodeFrom)) { __edges.emplace_back(nodeTo, nodeFrom); __data.push_back(link); EdgeId eid = __edges.size()-1; __outEdges.emplace(nodeFrom, eid); } } void - DFGraph::addTag(const SymbolPacked &node, Expression &&tag) { + DFAGraph::addTag(const SymbolPacked &node, Expression &&tag) { __tags.emplace(node, tag); } - SymbolPacked - DFGraph::pack(const Symbol& symbol, std::string hintSymbolName) - { - std::unordered_map::iterator pos - = __hash.emplace(symbol.scope, __hash.size()).first; - __hashedScopes.push_back(symbol.scope); - - SymbolPacked result; - result.scope = pos->second; - result.identifier = symbol.identifier; - } - - Symbol - DFGraph::unpack(const SymbolPacked& symbol) - { - return Symbol{symbol.identifier, __hashedScopes[symbol.scope]}; - }; - - bool SymbolPacked::isValid() const - { - return this->scope != SYMBOL_INVALID.scope && identifier != SYMBOL_INVALID.identifier; - } - bool operator==(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.identifier == s2.identifier && s1.scope == s2.scope; } bool operator<(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.scope < s2.scope || (s1.scope == s2.scope && s1.identifier < s2.identifier); } void ClaspLayer::registerdQuery(IQuery *query) { __queries.push_back(query); } -} \ No newline at end of file +} diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h index 3e883aa..9fb1f8f 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,173 +1,172 @@ #ifndef CLASPLAYER_H #define CLASPLAYER_H #include #include #include #include #include +#include namespace xreate { class CFGraph { friend class ClaspLayer; public: void addNode(unsigned int function, std::string &&tag); void addLink(unsigned int nodeFrom, unsigned int nodeTo); bool existsNode(unsigned int function) const; void print(std::ostream &cout) const; private: std::map __relations; std::map __nodes; }; - enum class DFGConnection{ - STRONG, OPT, PROTO}; - - struct SymbolPacked { VID identifier; unsigned int scope; - - bool isValid() const; }; bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); - const SymbolPacked SYMBOL_INVALID{UINT_MAX, UINT_MAX}; + enum class DFGConnection{ + ALIAS, OPT, PROTO}; - class DFGraph + class DFAGraph { friend class ClaspLayer; public: void addTag(const SymbolPacked& node, Expression&& tag); void addLink(const SymbolPacked& nodeTo, const SymbolPacked& nodeFrom, DFGConnection link); bool linkExists(const SymbolPacked& node1, const SymbolPacked& node2); - SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName=""); - Symbol unpack(const SymbolPacked& symbol); private: typedef unsigned int EdgeId; std::vector> __edges; std::multimap __outEdges; std::vector __data; std::multimap __tags; - - std::unordered_map __hash; - std::vector __hashedScopes; }; - class IQuery - { + class IQuery { public: virtual void init(ClaspLayer* clasp)=0; virtual ~IQuery() {} }; class ClaspLayer { public: AST *ast; - DFGraph dfgData; + DFAGraph dfaData; ClaspLayer(); void registerdQuery(IQuery* query); void addFunctionTags(const std::string &function, const std::vector &tags); void addCFAData(CFGraph &&graph); - void addDFAData(DFGraph &&graph); + void addDFAData(DFAGraph &&graph); void addRuleWarning(const RuleWarning &rule); void run(); template static std::tuple parse(const Gringo::Value& atom); typedef std::multimap::const_iterator ModelIterator; - std::pair query(const std::string& atom); + typedef boost::optional> ModelRange; + ModelRange query(const std::string& atom); + + SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName=""); + Symbol unpack(const SymbolPacked& symbol); private: // all query plugins to process clasp data std::list __queries; std::multimap __model; std::map __warnings; std::ostringstream __partTags; std::ostringstream __partGeneral; + std::unordered_map __indexScopes; + std::vector __registryScopes; + void printWarnings(std::ostream& out); bool onModel(Gringo::Model const &model); QStringList compile(const Expression &e) const; QStringList compileNeg(const Expression &e) const; unsigned int registerWarning(std::string &&message); void addImports(); + + }; template struct ParseImplAtom { static typ get(const Gringo::Value& atom) { return atom.num(); } }; template<> struct ParseImplAtom { static std::string get(const Gringo::Value& atom) { return *atom.string(); }}; template<> struct ParseImplAtom { static SymbolPacked get(const Gringo::Value& atom) { auto result = ClaspLayer::parse(atom); return SymbolPacked{std::get<0>(result), std::get<1>(result)}; }}; template<> struct ParseImplAtom { static Gringo::Value get(const Gringo::Value& atom) { return atom; }}; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::FWValVec::const_iterator arg) { const size_t tupleSize = std::tuple_size::value; typedef typename std::tuple_element::type ElType; ElType& el = std::get(tup); Gringo::Value atom = *arg; el = ParseImplAtom::get(atom); Parse_Impl::parse(tup, ++arg); } }; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::FWValVec::const_iterator arg) {} }; template std::tuple ClaspLayer::parse(const Gringo::Value& atom) { typedef std::tuple Tuple; Tuple tup; Parse_Impl::value>::parse(tup, atom.args().begin()); return tup; } } #endif diff --git a/cpp/src/instructions/instr-containers.cpp b/cpp/src/instructions/instr-containers.cpp index bbfb330..1cc1e05 100644 --- a/cpp/src/instructions/instr-containers.cpp +++ b/cpp/src/instructions/instr-containers.cpp @@ -1,276 +1,469 @@ #include "instr-containers.h" #include "llvmlayer.h" #include "ast.h" #include "query/containers.h" +#include "query/ptrvalid.h" using namespace std; using namespace llvm; +using namespace xreate; using namespace xreate::containers; -xreate::containers::Instructions::Instructions(CodeScope *current, LLVMLayer* layer) - : scope(current), llvm(layer), - tyNum (static_cast (TypeAnnotation(TypePrimitive::Num).toLLVMType())) -{} - -Value* -Instructions::compileIndex(const Symbol& dataSymbol, std::vector indexes, std::string ident) -{ - #define NAME(x) (ident.empty()? x : ident) - - const ImplementationData& info = containers::Query::queryImplementation(dataSymbol); - llvm::Value* data = dataSymbol.scope->__rawVars.at(dataSymbol.identifier); - - switch (info.impl) - { - case containers::LLVM_CONST_ARRAY: { - assert(indexes.size() == 1); - return llvm->builder.CreateExtractElement(data, indexes[0], NAME("el")); - } - - case containers::LLVM_ARRAY: { - indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); - Value *pEl = llvm->builder.CreateGEP(data, llvm::ArrayRef(indexes)); - return llvm->builder.CreateLoad(pEl, NAME("el")); - } - - default: - // non supported container implementation - assert(false); - } -} - -Value* -Instructions::compileGetElement(std::string varIn, Value* stateLoop, std::string ident) -{ - #define NAME(x) (ident.empty()? x : ident) - llvm::IRBuilder<> &builder = llvm->builder; - - const Symbol& symbolIn = scope->findSymbol(varIn, *llvm); - const Expression& exprIn = CodeScope::findDeclaration(symbolIn); - - if (exprIn.op == Operator::LIST_RANGE) - {return stateLoop; } - - if (exprIn.op == Operator::LIST) - { - llvm::Value* dataIn = CodeScope::compileExpression(symbolIn, *llvm); - return compileIndex(symbolIn, vector{stateLoop}, NAME(string("el_") + varIn)); - } - - if(exprIn.op == Operator::MAP) - { - assert(exprIn.getOperands().size()==1); - assert(exprIn.bindings.size()); - assert(exprIn.blocks.size()); - - const ManagedScpPtr& scopeLoop = exprIn.blocks.front(); - const std::string& varIn2 = exprIn.getOperands()[0].getValueString(); - std::string varEl = exprIn.bindings[0]; - - Value* elIn = compileGetElement(varIn2, stateLoop, varEl); - scopeLoop->bindArg(elIn, move(varEl)); - return scopeLoop->compileExpression(scopeLoop->__body, *llvm, NAME(string("el_") + varIn)); - } - - assert(false); - - +#define NAME(x) (hintRetVar.empty()? x : hintRetVar) - /* - switch(implIn.impl) - { - case containers::LLVM_ARRAY: - case containers::LLVM_CONST_ARRAY: - stateLoopNext = builder.CreateAdd(stateLoop, ConstantInt::get(tyNum, 1)); - - - case containers::ON_THE_FLY: - stateLoopNext = compileIndexLoad(stateLoad); - } - */ +#define EXPAND_CONTEXT \ + LLVMLayer* llvm = context.pass->man->llvm; \ + CompilePass::CodeScopeUnit* scope = context.scope; \ + CompilePass::FunctionUnit* function = context.function; \ -} +Instructions::Instructions(CompilePass::Context ctx) + : context(ctx), tyNum (static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) +{} llvm::Value* -Instructions::compileMapArray(const Expression &expr, const std::string ident) { - #define NAME(x) (ident.empty()? x : ident) +Instructions::compileMapSolid(const Expression &expr, const std::string hintRetVar) { + EXPAND_CONTEXT //initialization std::string varIn = expr.getOperands()[0].getValueString(); - Symbol symbolIn = scope->findSymbol(varIn, *llvm); + Symbol symbolIn = scope->scope->findSymbol(varIn); - containers::ImplementationData implIn = containers::Query::queryImplementation(symbolIn); // impl of input list - unsigned int size = implIn.size; - ManagedScpPtr scopeLoop = expr.blocks.front(); + ImplementationRec implIn = containers::Query::queryImplementation(symbolIn).extract(); // impl of input list + size_t size = implIn.size; + CodeScope* scopeLoop = expr.blocks.front(); std::string varEl = scopeLoop->__args[0]; - llvm::Value *rangeFrom = ConstantInt::get((tyNum), 0); - llvm::Value *rangeTo = ConstantInt::get((tyNum), size-1); + Iterator* it = Iterator::create(context, symbolIn); + llvm::Value *rangeFrom = it->begin(); + llvm::Value *rangeTo = it->end(); //definitions - ArrayType* tyNumArray = (ArrayType*) (TypeAnnotation(tag_array, TypePrimitive::Num, size).toLLVMType()); + ArrayType* tyNumArray = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Num, size)))); llvm::IRBuilder<> &builder = llvm->builder; - llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "loop", llvm->context.function); + llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "loop", function->raw); llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); - llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postloop", llvm->context.function); + llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postloop", function->raw); Value* dataOut = llvm->builder.CreateAlloca(tyNumArray, ConstantInt::get(tyNum, size), NAME("map")); // * initial check Value* condBefore = builder.CreateICmpSLE(rangeFrom, rangeTo); builder.CreateCondBr(condBefore, blockLoop, blockAfterLoop); // create PHI: builder.SetInsertPoint(blockLoop); llvm::PHINode *stateLoop = builder.CreatePHI(tyNum, 2, "mapIt"); stateLoop->addIncoming(rangeFrom, blockBeforeLoop); // loop body: - Value* elIn = compileGetElement(varIn, stateLoop, varEl); - scopeLoop->bindArg(elIn, move(varEl)); - Value* elOut = scopeLoop->compileExpression(scopeLoop->__body, *llvm); + Value* elIn = it->get(stateLoop, varEl); + CompilePass::CodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop); + scopeLoopUnit->bindArg(elIn, move(varEl)); + Value* elOut = scopeLoopUnit->compile(); Value *pElOut = builder.CreateGEP(dataOut, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), stateLoop})); builder.CreateStore(elOut, pElOut); //next iteration preparing Value *stateLoopNext = builder.CreateAdd(stateLoop,llvm::ConstantInt::get(tyNum, 1)); stateLoop->addIncoming(stateLoopNext, blockLoop); //next iteration checks: Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); //finalization: builder.SetInsertPoint(blockAfterLoop); return dataOut; } +Value* +Instructions::compileArrayIndex(const Symbol &dataSymbol, std::vector indexes, std::string hintRetVar) +{ + EXPAND_CONTEXT + + //TODO find out symbol identifier in order to name it in raw llvm; + llvm::Value* data = scope->compileSymbol(dataSymbol); + const Expression& decl = CodeScope::findDeclaration(dataSymbol); + + if (decl.op == Operator::LIST) { + assert(indexes.size() == 1); + return llvm->builder.CreateExtractElement(data, indexes[0], NAME("el")); + } + + + indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); + Value *pEl = llvm->builder.CreateGEP(data, llvm::ArrayRef(indexes)); + return llvm->builder.CreateLoad(pEl, NAME("el")); +} + +Value* +Instructions::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx){ + EXPAND_CONTEXT + + PointerType* tyInt8P = PointerType::getInt8PtrTy(llvm::getGlobalContext()); + Value* nullInt8P = llvm::ConstantPointerNull::get(tyInt8P); + + TypeUtils types(llvm); + + std::vector&& fields = types.getStructFields(t); + for (unsigned i=0, size = fields.size(); i refs; + + llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::ConstantInt* zero = llvm::ConstantInt::get(tyInt, 0, false); + + llvm::BasicBlock *blockSafe = llvm::BasicBlock::Create(llvm::getGlobalContext(), "safe", function->raw); + llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw); + + // safety check: not null ptr + Symbol s; + if (! QueryPtrValid::assertValidPtr(s)){ + PointerType* tyAggr = dyn_cast(aggregate->getType()); + llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr); + Value* condNull = llvm->builder.CreateICmpNE(aggregate, null); + llvm->builder.CreateCondBr(condNull, blockSafe, blockException); + } + + llvm->builder.SetInsertPoint(blockException); + + llvm->initExceptionsSupport(); + llvm::Function* fAllocate = llvm->module->getFunction("__cxa_allocate_exception"); + llvm::Function* fThrow = llvm->module->getFunction("__cxa_throw"); + auto exception = llvm->builder.CreateCall(fAllocate, ConstantInt::get(IntegerType::getInt64Ty(getGlobalContext()), 4)); + vector throwParams{exception, nullInt8P, nullInt8P}; + llvm->builder.CreateCall(fThrow, ArrayRef(throwParams)); + llvm->builder.CreateUnreachable(); + + + llvm->builder.SetInsertPoint(blockSafe); + std::vector indexes; + + //dereference pointer + if (types.isPointer(t)){ + indexes.push_back(zero); + } + indexes.push_back(ConstantInt::get(tyInt, i)); + + Value* addr = llvm->builder.CreateGEP(aggregate, indexes); + return llvm->builder.CreateLoad(addr); + + + } + } + + assert(false && "not found required struct field"); +} + llvm::Value* -Instructions::compileFold(const Expression& fold, const std::string& ident) +Instructions::compileFold(const Expression& fold, const std::string& hintRetVar) { - #define NAME(x) (ident.empty()? x : ident) + EXPAND_CONTEXT assert(fold.op == Operator::FOLD); //initialization: - Symbol varInSymbol = scope->findSymbol(fold.getOperands()[0].getValueString(), *llvm); - ImplementationData info = Query::queryImplementation(varInSymbol); - const pair& range = info.getRange(); - llvm::Value* rangeFrom = scope->compileExpression(range.first, *llvm); - llvm::Value* rangeTo = scope->compileExpression(range.second, *llvm); - llvm::Value* accumInit = scope->compileExpression(fold.getOperands()[1], *llvm); + Symbol varInSymbol = scope->scope->findSymbol(fold.getOperands()[0].getValueString()); + Implementation info = Query::queryImplementation(varInSymbol); + + Iterator* it = Iterator::create(context, varInSymbol); + llvm::Value* rangeFrom = it->begin(); + llvm::Value* rangeTo = it->end(); + llvm::Value* accumInit = scope->process(fold.getOperands()[1]); std::string varIn = fold.getOperands()[0].getValueString(); std::string varAccum = fold.bindings[1]; std::string varEl = fold.bindings[0]; llvm::Value* valSat; bool flagHasSaturation = false; //false; // TODO add `saturation` ann. llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); - llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", llvm->context.function); - llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postfold", llvm->context.function); + llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw); + llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postfold", function->raw); + llvm::BasicBlock *blockEarly = llvm::BasicBlock::Create(llvm::getGlobalContext(), "earlyret", function->raw); + + // * initial check - Value* condBefore = llvm->builder.CreateICmpSLE(rangeFrom, rangeTo); - llvm->builder.CreateCondBr(condBefore, blockLoop, blockAfterLoop); + Value* condBefore = llvm->builder.CreateICmpNE(rangeFrom, rangeTo); + llvm->builder.CreateCondBr(condBefore, blockLoop, blockEarly); + llvm->builder.SetInsertPoint(blockEarly); + llvm->builder.CreateRet(accumInit); + // Saturation check if (flagHasSaturation) { Value* condSat = llvm->builder.CreateICmpNE(accumInit, valSat); llvm->builder.CreateCondBr(condSat, blockLoop, blockAfterLoop); } // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(tyNum, 2, NAME("accum")); accum->addIncoming(accumInit, blockBeforeLoop); - - llvm::PHINode *stateLoop = llvm->builder.CreatePHI(tyNum, 2, "foldIt"); + llvm::PHINode *stateLoop = llvm->builder.CreatePHI(rangeFrom->getType(), 2, "foldIt"); stateLoop->addIncoming(rangeFrom, blockBeforeLoop); // * loop body - ManagedScpPtr scopeLoop = fold.blocks.front(); - Value* elIn = compileGetElement(varIn, stateLoop); - scopeLoop->bindArg(accum, move(varAccum)); - scopeLoop->bindArg(elIn, move(varEl)); - Value* accumNext = scopeLoop->compileExpression(scopeLoop->__body, *llvm); + CodeScope* scopeLoop = fold.blocks.front(); + CompilePass::CodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); + Value* elIn = it->get(stateLoop); + loopUnit->bindArg(accum, move(varAccum)); + loopUnit->bindArg(elIn, move(varEl)); + Value* accumNext = loopUnit->compile(); // * break checks, continue checks if (flagHasSaturation) { - llvm::BasicBlock *blockChecks = llvm::BasicBlock::Create(llvm::getGlobalContext(), "checks", llvm->context.function); + llvm::BasicBlock *blockChecks = llvm::BasicBlock::Create(llvm::getGlobalContext(), "checks", function->raw); Value* condSat = llvm->builder.CreateICmpNE(accumNext, valSat); llvm->builder.CreateCondBr(condSat, blockChecks, blockAfterLoop); llvm->builder.SetInsertPoint(blockChecks); } // * computing next iteration state - Value *stateLoopNext = llvm->builder.CreateAdd(stateLoop, llvm::ConstantInt::get(tyNum, 1)); + Value *stateLoopNext = it->move(stateLoop); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); stateLoop->addIncoming(stateLoopNext, llvm->builder.GetInsertBlock()); // * next iteration checks - Value* condAfter = llvm->builder.CreateICmpSLE(stateLoopNext, rangeTo); + Value* condAfter = llvm->builder.CreateICmpNE(stateLoopNext, rangeTo); llvm->builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); // finalization: llvm->builder.SetInsertPoint(blockAfterLoop); return accum; } llvm::Value* -Instructions::compileIf(const Expression& exprIf, const std::string& ident) +Instructions::compileIf(const Expression& exprIf, const std::string& hintRetVar) { - #define NAME(x) (ident.empty()? x : ident) + EXPAND_CONTEXT //initialization: const Expression& condExpr = exprIf.getOperands()[0]; llvm::IRBuilder<>& builder = llvm->builder; - llvm::BasicBlock *blockAfter = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifAfter", llvm->context.function); - llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifTrue", llvm->context.function); - llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifFalse", llvm->context.function); + llvm::BasicBlock *blockAfter = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifAfter", function->raw); + llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifTrue", function->raw); + llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifFalse", function->raw); - llvm::Value* cond = scope->compileExpression(condExpr, *llvm); + llvm::Value* cond = scope->process(condExpr); llvm->builder.CreateCondBr(cond, blockTrue, blockFalse); builder.SetInsertPoint(blockTrue); - ManagedScpPtr scopeTrue = exprIf.blocks.front(); - llvm::Value* resultTrue = scopeTrue->compileExpression(scopeTrue->__body, *llvm); + CodeScope* scopeTrue = exprIf.blocks.front(); + llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockFalse); - ManagedScpPtr scopeFalse = exprIf.blocks.back(); - llvm::Value* resultFalse = scopeFalse->compileExpression(scopeFalse->__body, *llvm); + CodeScope* scopeFalse = exprIf.blocks.back(); + llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockAfter); llvm::PHINode *ret = builder.CreatePHI(tyNum, 2, NAME("if")); ret->addIncoming(resultTrue, blockTrue); ret->addIncoming(resultFalse, blockFalse); return ret; } llvm::Value* Instructions::compileConstantArray(const Expression &expr, const std::string& hintRetVar) { - const int& __size = expr.getOperands().size(); + EXPAND_CONTEXT + + const size_t& __size = expr.getOperands().size(); const Expression& __data = expr; - ArrayType* typList = (ArrayType*) (TypeAnnotation(tag_array, TypePrimitive::i32, __size).toLLVMType()); - Type*typI32 = TypeAnnotation(TypePrimitive::i32).toLLVMType(); + ArrayType* typList = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I32, __size)))); + Type*typI32 = llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::I32))); std::vector list; list.reserve(__size); const std::vector operands = __data.getOperands(); std::transform(operands.begin(), operands.end(), std::inserter(list, list.begin()), [typI32](const Expression& e){return ConstantInt::get(typI32, e.getValueDouble());}); Value* listSource = ConstantArray::get(typList, ArrayRef(list)); /* Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); */ return listSource; -} \ No newline at end of file +} + +llvm::Value* +Instructions::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) +{ + EXPAND_CONTEXT + + size_t size = data.size(); + Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm::getGlobalContext())); + //ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1)))); + + /* + std::vector chars; + chars.reserve(size+1); + + for (size_t i=0; i< size; ++i){ + chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]); + } + chars[size] = ConstantInt::get(typI8, 0); + */ + + Value* rawData = ConstantDataArray::getString(llvm::getGlobalContext(), data); + Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 1, false)); + llvm->builder.CreateStore(rawData, rawPtrData); + return llvm->builder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); +} + + + +template +class IteratorForward; + +template<> +class IteratorForward : public Iterator { +private: + LLVMLayer* llvm; + const xreate::Symbol current; + const Symbol source; + const ImplementationLinkedList linkedlist; + CodeScope* const sourceScope; + //TODO initialize ans mark as const (three fields) + CompilePass::CodeScopeUnit* sourceUnit; + CompilePass::FunctionUnit* function; + const Expression& sourceDecl; + CompilePass::Context context; + llvm::Type* sourceRawType =nullptr; + +public: + IteratorForward(CompilePass::Context ctx, const xreate::Symbol& s, const ImplementationRec& implementation) + : context(ctx), source(implementation.source), current(s), sourceScope(source.scope), sourceDecl(CodeScope::findDeclaration(source)), + linkedlist(source), sourceUnit(new CompilePass::CodeScopeUnit(source.scope, ctx.function, ctx.pass)), llvm(ctx.pass->man->llvm) + { + } + + llvm::Value* begin() { + switch(sourceDecl.op) { + case xreate::Operator::LIST: + { + sourceRawType = Type::getInt32Ty(llvm::getGlobalContext()); + return ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 0); + }; + + case xreate::Operator::LIST_RANGE:{ + assert(sourceDecl.operands.size()==2); + + llvm::Value* result = sourceUnit->process(sourceDecl.operands.at(0)); + sourceRawType = result->getType(); + + return result; + }; + } + + if (linkedlist){ + llvm::Value* result = sourceUnit->process(sourceDecl); + sourceRawType = result->getType(); + return result; + } + + assert(false); + } + + llvm::Value* end(){ + switch(sourceDecl.op) { + case xreate::Operator::LIST: { + size_t idLast = sourceDecl.operands.size() - 1; + return ConstantInt::get(sourceRawType, idLast); + } + + case xreate::Operator::LIST_RANGE: { + assert(sourceDecl.operands.size() == 2); + return sourceUnit->process(sourceDecl.operands.at(1)); + }; + } + + //return null pointer + if (linkedlist){ + return ConstantPointerNull::getNullValue(sourceRawType); + } + } + + llvm::Value* get(Value* index,const std::string& hintRetVar="") override{ + const Expression& currentDecl = CodeScope::findDeclaration(current); + + switch (currentDecl.op) { + case xreate::Operator::LIST: { + llvm::Value* currentValue = sourceUnit->process(currentDecl); //TODO re check is it right scope(source) to compilation currentDecl + return Instructions(context).compileArrayIndex(current, vector{index}); + }; + + case xreate::Operator::LIST_RANGE: { + return index; + }; + + case xreate::Operator::MAP: { + assert(currentDecl.getOperands().size()==1); + assert(currentDecl.bindings.size()); + assert(currentDecl.blocks.size()); + + CodeScope* scopeLoop = currentDecl.blocks.front(); + const std::string& varIn = currentDecl.getOperands()[0].getValueString(); + std::string varEl = currentDecl.bindings[0]; + + const Symbol& symbIn = current.scope->findSymbol(varIn); + auto it = std::unique_ptr(Iterator::create(context, symbIn)); + + Value* elIn = it->get(index, varEl); + CompilePass::CodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); + unitLoop->bindArg(elIn, std::move(varEl)); + return unitLoop->compile(); + } + + case xreate::Operator::NONE: { + assert(currentDecl.__state==Expression::IDENT); + const Symbol& symbIn = current.scope->findSymbol(currentDecl.getValueString()); + auto it = std::unique_ptr(Iterator::create(context, symbIn)); + return it->get(index); + }; + } + + if (linkedlist){ + return index; + } + } + + llvm::Value* move(Value* index, const std::string& hintRetVar) override{ + switch(sourceDecl.op) + { + case xreate::Operator::LIST: + case xreate::Operator::LIST_RANGE: + return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1), hintRetVar); + } + + if (linkedlist){ + ExpandedType tySource = llvm->ast->expandType(sourceScope->findDefinition(source)); + assert(tySource->__operator == TypeOperator::ARRAY && "Linked list implementation has to have ARRAY type"); + assert(tySource->__operands.size()); + + return Instructions(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); + } + } +}; + +Iterator* +Iterator::create(CompilePass::Context context, const Symbol& var){ + + const Implementation& data = Query::queryImplementation(var); + + switch(data.impl){ + case ON_THE_FLY: + return new IteratorForward(context, var, data.extract()); + + default: assert(true); + } +} diff --git a/cpp/src/instructions/instr-containers.h b/cpp/src/instructions/instr-containers.h index bbb89fb..be660d1 100644 --- a/cpp/src/instructions/instr-containers.h +++ b/cpp/src/instructions/instr-containers.h @@ -1,76 +1,85 @@ #ifndef CODEINSTRUCTIONS_H #define CODEINSTRUCTIONS_H #include "llvmlayer.h" #include "ast.h" #include #include +#include "pass/compilepass.h" namespace xreate { namespace containers { +class Iterator{ +public : + virtual llvm::Value* begin() =0; + virtual llvm::Value* end() = 0; + virtual llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") = 0; + virtual llvm::Value* move(llvm::Value* index, const std::string& hintRetVar="")=0; + virtual ~Iterator(){}; + + static Iterator* create(CompilePass::Context context, const Symbol& var); +}; + class Instructions { public: - Instructions(CodeScope *current, LLVMLayer* layer); - llvm::Value* compileIndex(const Symbol& dataSymbol, std::vector indexes, std::string ident=""); - llvm::Value* compileGetElement(std::string varIn, llvm::Value* stateLoop, std::string ident=""); - + Instructions(CompilePass::Context ctx); + llvm::Value* compileArrayIndex(const Symbol &dataSymbol, std::vector indexes, std::string ident = ""); + llvm::Value* compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx); /* * - map Computation -> Llvm_Array: Prohibited, we do not know a result size * - map Llvm_Array -> Computation: considered in `compileGetElement` * - map Llvm_Array -> Llvm_Array considered by this method */ - llvm::Value* compileMapArray(const Expression &expr, const std::string hintRetVar=""); + llvm::Value*compileMapSolid(const Expression &expr, const std::string hintRetVar = ""); llvm::Value* compileFold(const Expression& fold, const std::string& ident=""); llvm::Value* compileIf(const Expression& exprIf, const std::string& ident); - - llvm::Value *compileConstantArray(const Expression &expr, const std::string& hintRetVar=""); + llvm::Value* compileConstantStringAsPChar(const string &data, const std::string& hintRetVar); + llvm::Value* compileConstantArray(const Expression &expr, const std::string& hintRetVar=""); private: - CodeScope* scope; - LLVMLayer* llvm; - + CompilePass::Context context; llvm::IntegerType* const tyNum; }; }} #endif //CODEINSTRUCTIONS_H /* template struct InstructionClasses {}; template<> struct InstructionClasses { typedef InstructionList Impl; }; template<> struct InstructionClasses { typedef InstructionMap Impl; }; template class CodeInstruction: public InstructionClasses::Impl { typedef typename InstructionClasses::Impl InstructionImpl; public: CodeInstruction(CodeScope* parent) : InstructionImpl(parent) {} llvm::Value * compileExpression(const Expression &expr, LLVMLayer &l, const std::string * const hintRetVar) { if (expr.op == Instruction) return InstructionImpl::compileDefault(expr, l, hintRetVar); return CodeScope::compileExpression(expr, l, hintRetVar); } }; } -*/ \ No newline at end of file +*/ diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index 192ec38..47121d3 100644 --- a/cpp/src/llvmlayer.cpp +++ b/cpp/src/llvmlayer.cpp @@ -1,15 +1,229 @@ +#include "ast.h" #include "llvmlayer.h" +#include "ExternLayer.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/Support/TargetSelect.h" +#include using namespace llvm; using namespace xreate; +using namespace std; -LLVMLayer::LLVMLayer() - :builder(getGlobalContext()) +LLVMLayer::LLVMLayer(AST* root) + :builder(getGlobalContext()), ast(root) { + module = new llvm::Module(root->getModuleName(), llvm::getGlobalContext()); + layerExtern = new ExternLayer(this); + layerExtern->init(root); +} + +void* +LLVMLayer::getFunctionPointer(llvm::Function* function){ + uint64_t entryAddr = jit->getFunctionAddress(function->getName().str()); + return (void*) entryAddr; +} + +void +LLVMLayer::initJit(){ + std::string ErrStr; + LLVMInitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + llvm::EngineBuilder builder((std::unique_ptr(module))); + jit = builder + .setEngineKind(llvm::EngineKind::JIT) + .setErrorStr(&ErrStr) + .setVerifyModules(true) + .create(); +} + +void +LLVMLayer::print(){ + llvm::PassManager PM; + PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner")); + PM.run(*module); } void LLVMLayer::moveToGarbage(void *o) { __garbage.push_back(o); } + +llvm::Type* +LLVMLayer:: +toLLVMType(const ExpandedType& ty) const { + std::map empty; + return toLLVMType(ty, empty); +} + +llvm::Type* +LLVMLayer:: +toLLVMType(const ExpandedType& ty, std::map& conjuctions) const +{ + TypeAnnotation t = ty; + switch (t.__operator) + { + case TypeOperator::ARRAY: + { + assert(t.__operands.size()==1); + + TypeAnnotation elTy = t.__operands.at(0); + return llvm::ArrayType::get(toLLVMType(ExpandedType(move(elTy)), conjuctions), t.__size); + } + + case TypeOperator::STRUCT: + case TypeOperator::TUPLE: + { + assert(t.__operands.size()); + + std::vector pack_; + pack_.reserve(t.__operands.size()); + + std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack_, pack_.end()), + [this, &conjuctions](const TypeAnnotation& t){ + return toLLVMType(ExpandedType(TypeAnnotation(t)), conjuctions); + }); + + llvm::ArrayRef pack(pack_); + + //process recursive types: + if (conjuctions.count(t.conjuctionId)) { + auto result = conjuctions[t.conjuctionId]; + result->setBody(pack, false); + + return result; + } + + return llvm::StructType::get(llvm::getGlobalContext(), pack, false); + }; + + case TypeOperator::LINK: { + llvm::StructType* conjuction = llvm::StructType::create(llvm::getGlobalContext()); + int id = t.conjuctionId; + + conjuctions.emplace(id, conjuction); + return conjuction; + }; + + case TypeOperator::CALL: + { + assert(false); + }; + + case TypeOperator::CUSTOM: + { + //Look in extern types + + clang::QualType qt = layerExtern->lookupType(t.__valueCustom); + return layerExtern->toLLVMType(qt); + }; + + case TypeOperator::NONE: { + switch (t.__value) { + case TypePrimitive::Bool: + return llvm::Type::getInt1Ty(llvm::getGlobalContext()); + + case TypePrimitive::I32: + case TypePrimitive::Int: + case TypePrimitive::Num: + return llvm::Type::getInt32Ty(llvm::getGlobalContext()); + + case TypePrimitive::I8: + return llvm::Type::getInt8Ty(llvm::getGlobalContext()); + + case TypePrimitive::Float: + return llvm::Type::getDoubleTy(llvm::getGlobalContext()); + + case TypePrimitive::String: + return llvm::Type::getInt8PtrTy(llvm::getGlobalContext()); + + default: + assert(false); + } + } + + default: + assert(false); + } + + assert(false); + return nullptr; +} + +void +LLVMLayer::initExceptionsSupport(){ + Type* typInt8Ptr = PointerType::get(IntegerType::get(module->getContext(), 8), 0); + + if (!module->getFunction("__cxa_throw")) { + std::vector fThrowSignature{typInt8Ptr, typInt8Ptr, typInt8Ptr}; + + FunctionType* tyFThrow = FunctionType::get( + /*Result=*/Type::getVoidTy(module->getContext()), + /*Params=*/fThrowSignature, + /*isVarArg=*/false); + + llvm::Function::Create( + /*Type=*/tyFThrow, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"__cxa_throw", module); // (external, no body) + } + + if (!module->getFunction("__cxa_allocate_exception")) { + std::vectorfAllocateSignature{IntegerType::get(module->getContext(), 64)}; + + FunctionType* tyFAllocate = FunctionType::get( + /*Result=*/typInt8Ptr, + /*Params=*/fAllocateSignature, + /*isVarArg=*/false); + + llvm::Function::Create( + /*Type=*/tyFAllocate, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"__cxa_allocate_exception", module); // (external, no body) + } +} + +bool TypeUtils::isStruct(const ExpandedType& ty){ + const TypeAnnotation& t = ty.get(); + + if (t.__operator==TypeOperator::STRUCT) { + return true; + } + + if (t.__operator != TypeOperator::CUSTOM) { + return false; + } + + clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom); + const clang::Type * raw = tqual.getTypePtr(); + + // TODO skip ALL the pointers until non-pointer type found + if (raw->isStructureType()) return true; + if (!raw->isAnyPointerType()) return false; + + const clang::PointerType* tPtr = raw->getAs(); + clang::QualType pointee = raw->getPointeeType(); + const clang::Type * pointeeRaw = pointee.getTypePtr(); + return pointee->isStructureType(); +} + + +bool TypeUtils::isPointer(const ExpandedType &ty) { + if (ty.get().__operator != TypeOperator::CUSTOM) return false; + + clang::QualType qt = llvm->layerExtern->lookupType(ty.get().__valueCustom); + return llvm->layerExtern->isPointer(qt); +} + + +std::vector +TypeUtils::getStructFields(const ExpandedType &t) { + return (t.get().__operator == TypeOperator::STRUCT) + ? t.get().fields + : llvm->layerExtern->getStructFields( + llvm->layerExtern->lookupType(t.get().__valueCustom)); +} + + diff --git a/cpp/src/llvmlayer.h b/cpp/src/llvmlayer.h index 937143c..3079d28 100644 --- a/cpp/src/llvmlayer.h +++ b/cpp/src/llvmlayer.h @@ -1,38 +1,56 @@ #ifndef LLVMLAYER_H #define LLVMLAYER_H #include "llvm/IR/Module.h" #include "llvm/IR/Function.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Verifier.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" #include "utils.h" -//#include "ast.h" + namespace xreate { class AST; + class ExternLayer; + class TypeAnnotation; class LLVMLayer { public: - LLVMLayer(); + LLVMLayer(AST* rootAST); - AST *ast; - llvm::Module *module; + AST *ast = 0; + ExternLayer *layerExtern =0; + llvm::Module *module = 0; + llvm::ExecutionEngine* jit= 0; llvm::IRBuilder<> builder; - struct { - llvm::Function* function = 0; - } context; - void moveToGarbage(void *o); - llvm::Value *compile() const; + llvm::Type* toLLVMType(const Expanded& ty) const; + void print(); + void* getFunctionPointer(llvm::Function* function); + void initJit(); + void initExceptionsSupport(); private: + llvm::Type* toLLVMType(const Expanded& ty, std::map& conjunctions) const; std::vector __garbage; }; + + struct TypeUtils { + bool isStruct(const Expanded& ty); + bool isPointer(const Expanded& ty); + std::vector getStructFields(const Expanded& t); + + TypeUtils(LLVMLayer*llvmlayer) + : llvm(llvmlayer){} + + private: + LLVMLayer* llvm; + }; } #endif // LLVMLAYER_H diff --git a/cpp/src/pass/abstractpass.cpp b/cpp/src/pass/abstractpass.cpp index a729a75..8ca4dc2 100644 --- a/cpp/src/pass/abstractpass.cpp +++ b/cpp/src/pass/abstractpass.cpp @@ -1,90 +1,15 @@ #include "abstractpass.h" #include "attachments.h" +#include "passmanager.h" + using namespace std; namespace xreate { - void - AbstractPass::process(ManagedRulePtr rule) - {} - - void - AbstractPass::process(ManagedFnPtr function) { - PassContext context; - context.function = function; - - process(function->getEntryScope(), context); - } - - void - AbstractPass::process(CodeScope *scope, PassContext context) { - context.scope = scope; - process(scope->__body, context); - } - - void - AbstractPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ - switch (expression.__state) { - case Expression::COMPOUND: - for (const Expression &op: expression.getOperands()) { - process(op, context); - } - - assert(expression.op != Operator::MAP || expression.op == Operator::MAP && expression.blocks.size()); - for (ManagedScpPtr scope: expression.blocks) { - process(&*scope, context); - } - - /* - if (expression.op == Operator::CALL) { - const std::string &calleeName = expression.getValueString(); - ManagedFnPtr callee = root->findFunction(calleeName); - } - */ - break; - - case Expression::IDENT: - assert(context.scope); - - string ident = expression.getValueString(); - const Symbol& symbol = context.scope->findSymbol(ident, *man->llvm); - - if (SymbolAttachments::get (symbol, false)) {break;} - SymbolAttachments::put (symbol, true); - - PassContext context2 = context; - context2.scope = symbol.scope; - if (CodeScope::hasDeclaration(symbol)) { - process(CodeScope::findDeclaration(symbol), context2, ident); - } - - break; - } - } - - void - AbstractPass::processFnCall(ManagedFnPtr function, PassContext context) - { - } - - void - AbstractPass::run() { - ManagedRulePtr rule = man->root->begin(); - while (rule.isValid()) { - process(rule); - ++rule; - } - - ManagedFnPtr f = man->root->begin(); - while (f.isValid()) { - process(f); - ++f; - } - } - void AbstractPass::finish() + void AbstractPassBase::finish() {} - AbstractPass::AbstractPass(PassManager *manager) + AbstractPassBase::AbstractPassBase(PassManager *manager) : man(manager) { } -} \ No newline at end of file +} diff --git a/cpp/src/pass/abstractpass.h b/cpp/src/pass/abstractpass.h index a49d1a1..89e74ec 100644 --- a/cpp/src/pass/abstractpass.h +++ b/cpp/src/pass/abstractpass.h @@ -1,38 +1,121 @@ #ifndef ABSTRACTPASS_H #define ABSTRACTPASS_H - +#include "ast.h" #include "passmanager.h" +#include +using namespace std; namespace xreate { struct PassContext { CodeScope* scope = 0; ManagedFnPtr function; ManagedRulePtr rule; std::string varDecl; PassContext() {} + PassContext&& updateScope(CodeScope* scopeNew) { + PassContext context2{*this}; + context2.scope = scopeNew; + return std::move(context2); + } + ~PassContext(){} }; - class AbstractPass - { + class PassManager; + + class AbstractPassBase { public: - AbstractPass(PassManager* man); - virtual void run(); + AbstractPassBase(PassManager* manager); + virtual void run()=0; virtual void finish(); - virtual void processFnCall(ManagedFnPtr function, PassContext context); - virtual void process(ManagedFnPtr function); - virtual void process(ManagedRulePtr rule); - virtual void process(CodeScope* scope, PassContext context); - virtual void process(const Expression& expression, PassContext context, const std::string& varDecl=""); - - protected: PassManager* man; }; + + template + class AbstractPass: public AbstractPassBase { + private: + std::set __visitedSymbols; + + public: + AbstractPass(PassManager* manager): AbstractPassBase(manager) {} + + //NOTE implement processFnCall + virtual void processFnCall(ManagedFnPtr function, PassContext context) + {} + + virtual void process(ManagedRulePtr rule) + {} + + virtual Output process(ManagedFnPtr function){ + PassContext context; + context.function = function; + + return process(function->getEntryScope(), context); + } + + virtual Output process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""){ + context.scope = scope; + return process(scope->__body, context); + } + + virtual Output process(const Expression& expression, PassContext context, const std::string& varDecl=""){ + switch (expression.__state) { + case Expression::COMPOUND: + for (const Expression &op: expression.getOperands()) { + process(op, context); + } + + assert(expression.op != Operator::MAP || expression.op == Operator::MAP && expression.blocks.size()); + for (CodeScope* scope: expression.blocks) { + process(scope, context); + } + + /* + if (expression.op == Operator::CALL) { + const std::string &calleeName = expression.getValueString(); + ManagedFnPtr callee = root->findFunction(calleeName); + } + */ + break; + + case Expression::IDENT: + assert(context.scope); + + std::string ident = expression.getValueString(); + const Symbol& symbol = context.scope->findSymbol(ident); + + if (__visitedSymbols.count(symbol)) {break;} + __visitedSymbols.insert(symbol); + + PassContext context2 = context; + context2.scope = symbol.scope; + if (CodeScope::hasDeclaration(symbol)) { + process(CodeScope::findDeclaration(symbol), context2, ident); + } + + break; + } + } + + void run() { + ManagedRulePtr rule = man->root->begin(); + while (rule.isValid()) { + process(rule); + ++rule; + } + + ManagedFnPtr f = man->root->begin(); + while (f.isValid()) { + process(f); + ++f; + } + } + }; } -#endif \ No newline at end of file +#endif diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp new file mode 100644 index 0000000..e374bc8 --- /dev/null +++ b/cpp/src/pass/compilepass.cpp @@ -0,0 +1,449 @@ +#include "compilepass.h" +#include "clasplayer.h" +#include +#include +#include "query/containers.h" +#include "instructions/instr-containers.h" +#include "ExternLayer.h" + +using namespace std; +using namespace xreate; +using namespace llvm; + +CompilePass::CodeScopeUnit::CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) + : scope(codeScope), pass(compilePass), function(f) +{} + +void +CompilePass::CodeScopeUnit::bindArg(llvm::Value* var, std::string&& name) +{ + assert(scope->__vartable.count(name)); + VID id = scope->__vartable.at(name); + __rawVars[id] = var; +} + +llvm::Value* +CompilePass::CodeScopeUnit::convertType(llvm::Value* source, llvm::Type* tyTarget){ + LLVMLayer* llvm = pass->man->llvm; + + if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) + { + llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); + llvm::IntegerType* tySourceInt = llvm::dyn_cast(source->getType()); + + if (tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()){ + return llvm->builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget); + } + + if (tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()){ + return llvm->builder.CreateCast(llvm::Instruction::SExt, source, tyTarget); + } + } + + assert(false && "no automatic type conversion possible"); +} + +llvm::Value* +CompilePass::CodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl){ +#define VARNAME(x) (hintVarDecl.empty()? x: hintVarDecl) + llvm::Value *left; llvm::Value *right; + LLVMLayer& l = *pass->man->llvm; + CompilePass::Context context{function, this, pass}; + containers::Instructions instructions = containers::Instructions(context); + + switch (expr.op) { + case Operator::ADD: + case Operator::SUB: + case Operator::MUL: + case Operator::DIV: + case Operator::EQU: + case Operator::LSS: + case Operator::GTR: + assert(expr.__state == Expression::COMPOUND); + assert(expr.operands.size() == 2); + + left = process(expr.operands[0]); + right = process(expr.operands[1]); + + if (left->getType()!= right->getType()) { + right = convertType(right, left->getType()); + } + break; + + default:; + } + + switch (expr.op) { + case Operator::ADD: + return l.builder.CreateAdd(left, right, VARNAME("tmp_add")); + break; + + case Operator::SUB: + return l.builder.CreateSub(left, right, VARNAME("tmp_sub")); + break; + + case Operator::MUL: + return l.builder.CreateMul(left, right, VARNAME("tmp_mul")); + break; + + case Operator::DIV: + return l.builder.CreateSDiv(left, right, VARNAME("tmp_div")); + break; + + case Operator::EQU: + left->dump(); + right->dump(); + return l.builder.CreateICmpEQ(left, right, VARNAME("tmp_equ")); + break; + + case Operator::LSS: + return l.builder.CreateICmpSLT(left, right, VARNAME("tmp_lss")); + break; + + case Operator::GTR: + return l.builder.CreateICmpSGT(left, right, VARNAME("tmp_gtr")); + break; + + case Operator::NEG: + left = process(expr.operands[0]); + return l.builder.CreateNeg(left, VARNAME("tmp_neg")); + break; + + case Operator::CALL: { + assert(expr.__state == Expression::COMPOUND); + + std::string fname = expr.getValueString(); + + + std::vector args; + args.reserve(expr.operands.size()); + + std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), + [this](const Expression &operand) { + return process(operand); + } + ); + + FunctionUnit* calleeUnit = pass->getFunctionUnit(string(fname)); + + // external function + if (!calleeUnit) { + llvm::Function* external = pass->man->llvm->layerExtern->lookupFunction(fname); + return l.builder.CreateCall(external, args, hintVarDecl); + } + + if (calleeUnit->isInline()) { + return calleeUnit->compileInline(move(args), this->function); + } + + llvm::BasicBlock* blockPrev = pass->man->llvm->builder.GetInsertBlock(); + llvm::Value* callee = calleeUnit->compile(); + pass->man->llvm->builder.SetInsertPoint(blockPrev); + return l.builder.CreateCall(callee, args, hintVarDecl); + } + + case Operator::IF: + { + return instructions.compileIf(expr, hintVarDecl); + } + + case Operator::LIST: + { + return instructions.compileConstantArray(expr, hintVarDecl); + }; + + case Operator::LIST_RANGE: + { + assert(false); //no compilation phase for a range list + // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); + }; + + case Operator::LIST_NAMED: + { + typedef Expanded ExpandedType; + + ExpandedType tyRaw = l.ast->expandType(expr.type); + + const std::vector fields = (tyRaw.get().__operator == TypeOperator::CUSTOM)? + l.layerExtern->getStructFields(l.layerExtern->lookupType(tyRaw.get().__valueCustom)) + : tyRaw.get().fields; + + std::map indexFields; + for(size_t i=0, size = fields.size(); i(l.toLLVMType(tyRaw)); + llvm::Value* record = llvm::UndefValue::get(tyRecord); + + for (int i=0; igetElementType(fieldId); + result = llvm::UndefValue::get(tyNullField); + + } else { + result = process(operand); + } + + assert (result); + record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef({fieldId})); + } + + return record; + }; + + + + case Operator::MAP: + { + assert(expr.blocks.size()); + return instructions.compileMapSolid(expr, VARNAME("map")); + }; + + case Operator::FOLD: + { + return instructions.compileFold(expr, VARNAME("fold")); + }; + + case Operator::INDEX: + { + //TODO allow multiindex + assert(expr.operands.size()==1); + const std::string &ident = expr.getValueString(); + Symbol s = scope->findSymbol(ident); + const TypeAnnotation& t = s.scope->findDefinition(s); + const ExpandedType& t2 = pass->man->root->expandType(t); + + switch (t2.get().__operator) + { + case TypeOperator::STRUCT: case TypeOperator::CUSTOM: + { + Expression idx = expr.operands.at(0); + assert(idx.__state == Expression::STRING); + std::string idxField = idx.getValueString(); + + llvm::Value* aggr = compileSymbol(s, ident); + return instructions.compileStructIndex(aggr, t2, idxField); + }; + + case TypeOperator::ARRAY: { + std::vector indexes; + std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), + [this] (const Expression& op){return process(op);} + ); + + return instructions.compileArrayIndex(s, indexes, VARNAME(string("el_") + ident)); + }; + + default: + assert(false); + } + }; + + + case Operator::NONE: + assert(expr.__state != Expression::COMPOUND); + + switch (expr.__state) { + case Expression::IDENT: { + const std::string &ident = expr.getValueString(); + Symbol s = scope->findSymbol(ident); + return compileSymbol(s, ident); + } + + case Expression::NUMBER: { + int literal = expr.getValueDouble(); + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), literal); + } + + case Expression::STRING: { + return instructions.compileConstantStringAsPChar(expr.getValueString(), hintVarDecl); + }; + + + }; + + break; + + } + + assert(false); + return 0; +} + +llvm::Value* +CompilePass::CodeScopeUnit::compile(const std::string& hintBlockDecl){ + if (raw != nullptr) return raw; + + + if (!hintBlockDecl.empty()) { + llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw); + pass->man->llvm->builder.SetInsertPoint(block); + } + + raw = process(scope->__body); + return raw; +} + +llvm::Value* +CompilePass::CodeScopeUnit::compileSymbol(const Symbol& s, std::string hintRetVar) +{ + CodeScope* scope = s.scope; + CodeScopeUnit* self = function->getScopeUnit(scope); + + if (self->__rawVars.count(s.identifier)) { + return self->__rawVars[s.identifier]; + } + + return self->__rawVars[s.identifier] = self->process(scope->findDeclaration(s), hintRetVar); +} + +bool +CompilePass::FunctionUnit::isInline(){ + Symbol ret = Symbol{0, function->__entry}; + bool flagOnTheFly = SymbolAttachments::get(ret, false); + + return flagOnTheFly; +} + +llvm::Function* +CompilePass::FunctionUnit::compile(){ + if (raw != nullptr) return raw; + + std::vector types; + LLVMLayer* llvm = pass->man->llvm; + CodeScope* entry = function->__entry; + + std::transform(entry->__args.begin(), entry->__args.end(), std::inserter(types, types.end()), + [this, llvm, entry](const std::string &arg)->llvm::Type* { + assert(entry->__vartable.count(arg)); + VID argid = entry->__vartable.at(arg); + assert(entry->__definitions.count(argid)); + return llvm->toLLVMType(pass->man->root->expandType(entry->__definitions.at(argid))); + }); + + llvm::FunctionType *ft = llvm::FunctionType::get(llvm->toLLVMType(pass->man->root->expandType(entry->__definitions[0])), types, false); + raw = llvm::cast(llvm->module->getOrInsertFunction(function->__name, ft)); + + CodeScopeUnit* entryCompilation = getScopeUnit(entry); + llvm::Function::arg_iterator fargsI = raw->arg_begin(); + for (std::string &arg : entry->__args) { + VID argid = entry->__vartable[arg]; + + entryCompilation->__rawVars[argid] = fargsI; + fargsI->setName(arg); + ++fargsI; + } + + const std::string blockName = "entry"; + llvm->builder.CreateRet(entryCompilation->compile(blockName)); + + llvm->moveToGarbage(ft); + return raw; +} + +//TEST FunctionUnit::compileInline +llvm::Value* +CompilePass::FunctionUnit::compileInline(std::vector &&args, CompilePass::FunctionUnit* outer){ + CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); + for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__args.at(i))); + } + + + return entryCompilation->compile(); +} + +CompilePass::CodeScopeUnit* +CompilePass::FunctionUnit::getScopeUnit(CodeScope* scope){ + if (!scopes.count(scope)){ + CodeScopeUnit* unit = new CodeScopeUnit(scope, this, pass); + scopes.emplace(scope, std::unique_ptr(unit)); + } + + return scopes.at(scope).get(); +} + +CompilePass::CodeScopeUnit* +CompilePass::FunctionUnit::getEntry(){ + return getScopeUnit(function->getEntryScope()); +} + +CompilePass::CodeScopeUnit* +CompilePass::FunctionUnit::getScopeUnit(ManagedScpPtr scope){ + return getScopeUnit(&*scope); +} + +CompilePass::FunctionUnit* +CompilePass::getFunctionUnit(const CompilePass::FunctionQuery& f){ + ManagedFnPtr fkey = man->root->findFunction(f.name); + + //external functions: + if (!fkey){ + return nullptr; + } + + if (!functions.count(&*fkey)){ + functions.emplace(&*fkey, std::unique_ptr(new FunctionUnit(fkey, this))); + } + + return functions.at(&*fkey).get(); +} + +void +CompilePass::run(){ + //Find out main function; + ClaspLayer::ModelRange model = man->clasp->query(Config::get("function-entry")); + assert(model && "Error: No entry function found"); + assert(model->first != model->second && "Error: Ambiguous entry function"); + + string nameMain = std::get<0>(ClaspLayer::parse(model->first->second)); + FunctionUnit* unitMain = getFunctionUnit(move(nameMain)); + entry = unitMain->compile(); +} + +llvm::Function* +CompilePass::getEntryFunction(){ + assert(entry); + return entry; +} + + +//CODESCOPE COMPILATION PHASE + + +//FIND SYMBOL(compilation phase): + //if (!forceCompile) + //{ + // return result; + //} + + // //search in already compiled vars + //if (__rawVars.count(vId)) + //{ + // return result; + //} + + //if (!__declarations.count(vId)) { + // //error: symbol is uncompiled scope arg + // assert(false); + //} + + //const Expression& e = __declarations.at(vId); + + //__rawVars[vId] = process(e, l, name); + + +//FIND FUNCTION + //llvm::Function* + //CompilePass::findFunction(const std::string& name){ + // ManagedFnPtr calleeFunc = man->root->findFunction(name); + // assert(calleeFunc.isValid()); + + // return nullptr; + //} diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h new file mode 100644 index 0000000..a135d6c --- /dev/null +++ b/cpp/src/pass/compilepass.h @@ -0,0 +1,82 @@ +#ifndef COMPILEPASS_H +#define COMPILEPASS_H + +#include "abstractpass.h" +#include "llvm/IR/Function.h" + +namespace xreate { + + + +class CompilePass : public AbstractPass +{ +public: + + class CodeScopeUnit; + class FunctionUnit{ + public: + FunctionUnit(ManagedFnPtr f, CompilePass* p) + : function(f), pass(p) {} + + llvm::Value* compileInline(std::vector&& args, CompilePass::FunctionUnit* outer); + bool isInline(); + llvm::Function* compile(); + + CodeScopeUnit* getEntry(); + CodeScopeUnit* getScopeUnit(CodeScope* scope); + CodeScopeUnit* getScopeUnit(ManagedScpPtr scope); + + ManagedFnPtr function; + llvm::Function* raw = nullptr; + private: + CompilePass* pass; + std::map> scopes; + }; + + class CodeScopeUnit { + public: + CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); + + void bindArg(llvm::Value* var, std::string&& name); + std::map __rawVars; + + llvm::Value* compile(const std::string& hintBlockDecl=""); + llvm::Value* compileSymbol(const Symbol& s, std::string hintRetVar=""); + llvm::Value* process(const Expression& expr, const std::string& hintVarDecl=""); + CodeScope* scope; + + private: + CompilePass* pass; + llvm::Value* raw = nullptr; + FunctionUnit* function; + + llvm::Value* convertType(llvm::Value* source, llvm::Type* tyTarget); + }; + + struct Context{ + FunctionUnit* function; + CodeScopeUnit* scope; + CompilePass* pass; + }; + + struct FunctionQuery{ + FunctionQuery(std::string&& functionName): name(functionName) {} + + std::string name; + }; + + CompilePass(PassManager* manager): AbstractPass(manager) {} + FunctionUnit* getFunctionUnit(const FunctionQuery& f); + void run() override; + llvm::Function* getEntryFunction(); + +private: + std::map> functions; + llvm::Function* entry = 0; + + +}; + +} + +#endif // COMPILEPASS_H diff --git a/cpp/src/pass/dfgpass.cpp b/cpp/src/pass/dfgpass.cpp index 3586b0b..9026b78 100644 --- a/cpp/src/pass/dfgpass.cpp +++ b/cpp/src/pass/dfgpass.cpp @@ -1,144 +1,152 @@ -#include #include "dfgpass.h" #include "../passmanager.h" using namespace xreate; using namespace std; DFGPass::DFGPass(PassManager* manager) - : AbstractPass(manager) + : AbstractPass(manager), clasp(man->clasp) {} - -SymbolPacked -DFGPass::processExpression(const Expression& expression, PassContext context, const std::string& decl) +SymbolPackedOptional +DFGPass::process(const Expression& expression, PassContext context, const std::string& decl) { + // write down adhoc expression tags: + if (expression.tags.size() && decl.length()) { + for (pair tag: expression.tags) { + SymbolPacked nodeThis = clasp->pack(context.scope->findSymbol(decl), decl); + __context.graph.addTag(nodeThis, Expression(tag.second)); + } + } + + switch(expression.__state) { + case Expression::IDENT: + AbstractPass::process(expression, context, decl); + + string ident = expression.getValueString(); + const Symbol& identSymbol = context.scope->findSymbol(ident); + + SymbolPacked nodeFrom = clasp->pack(identSymbol); + if (!decl.empty()) { + SymbolPacked nodeTo = clasp->pack(context.scope->findSymbol(decl)); + __context.graph.addLink(move(nodeTo), move(nodeFrom), DFGConnection::ALIAS); + } + + return nodeFrom; + } + switch(expression.op) { case Operator::CALL: { const string &name = expression.getValueString(); - ManagedFnPtr function = man->root->findFunction(name); - CodeScope *scopeRemote = function->getEntryScope(); - std::vector operands; + + std::vector operands; operands.reserve(expression.getOperands().size()); for (const Expression &op: expression.getOperands()) { - operands.push_back(processExpression(op, context)); + operands.push_back(process(op, context)); } - std::vector::iterator op = operands.begin(); + ManagedFnPtr function = man->root->findFunction(name); + if (!function) return boost::none; + + // set calling relations: + CodeScope *scopeRemote = function->getEntryScope(); + std::vector::iterator op = operands.begin(); for (const std::string &arg: scopeRemote->__args) { - if (op->isValid()) { - const Symbol &nodeRemote = scopeRemote->findSymbol(arg, *man->llvm, false); - __context.graph.addLink(__context.graph.pack(nodeRemote), *op, DFGConnection::OPT); + if (*op) { + const Symbol &nodeRemote = scopeRemote->findSymbol(arg); + __context.graph.addLink(clasp->pack(nodeRemote), **op, DFGConnection::OPT); } ++op; } - SymbolPacked ret = __context.graph.pack(Symbol{0, scopeRemote}); + SymbolPacked ret = clasp->pack(Symbol{0, scopeRemote}); if (!decl.empty()) { __context.graph.addLink( - __context.graph.pack( - context.scope->findSymbol(decl, *man->llvm, false)), + clasp->pack( + context.scope->findSymbol(decl)), ret, DFGConnection::OPT); } return ret; } + } - default: { - std::vector operands; - - if (__schemes.count(expression.op)) { - const Expression &scheme = __schemes.at(expression.op); - - operands.reserve(expression.getOperands().size()); - for (const Expression &op: expression.getOperands()) { - operands.push_back(processExpression(op, context)); - } - - std::vector::const_iterator arg = operands.begin(); - std::vector::const_iterator tag = ++scheme.getOperands().begin(); + std::vector operands; - while (tag != scheme.getOperands().end()) { - if (arg->isValid() && tag->__state != Expression::INVALID) { - __context.graph.addTag(*arg, Expression(*tag)); - } + if (__signatures.count(expression.op)) { + const Expression &scheme = __signatures.at(expression.op); - ++arg; ++tag; - } + operands.reserve(expression.getOperands().size()); + for (const Expression &op: expression.getOperands()) { + operands.push_back(process(op, context)); + } - Expression retTag = *scheme.getOperands().begin(); - if (retTag.__state != Expression::INVALID) { - assert(!decl.empty()); - SymbolPacked pdecl = __context.graph.pack(context.scope->findSymbol(decl, *man->llvm, false)); - __context.graph.addTag(pdecl, move(retTag)); - } - } + std::vector::const_iterator arg = operands.begin(); + std::vector::const_iterator tag = ++scheme.getOperands().begin(); - // adhoc for MAP case, TODO reorganize code in more clear manner - if (expression.op == Operator::MAP) { - SymbolPacked nodeFrom; + while (tag != scheme.getOperands().end()) { + if (*arg && tag->__state != Expression::INVALID) { + __context.graph.addTag(**arg, Expression(*tag)); + } - if (operands.size()) { - nodeFrom = operands.at(0); - } else { - nodeFrom = processExpression(expression.getOperands().at(0), context); - } + ++arg; ++tag; + } - assert(!decl.empty()); - SymbolPacked nodeTo = __context.graph.pack(context.scope->findSymbol(decl, *man->llvm, false)); - __context.graph.addLink(move(nodeTo), move(nodeFrom), DFGConnection::PROTO); - } - } + Expression retTag = *scheme.getOperands().begin(); + if (retTag.__state != Expression::INVALID) { + assert(!decl.empty()); + SymbolPacked pdecl = clasp->pack(context.scope->findSymbol(decl)); + __context.graph.addTag(pdecl, move(retTag)); + } + } - } + // adhoc for MAP case, TODO reorganize code in more clear manner + if (expression.op == Operator::MAP) { + SymbolPackedOptional nodeFrom; - switch(expression.__state) { - case Expression::IDENT: - AbstractPass::process(expression, context, decl); + if (operands.size()) { + nodeFrom = operands.at(0); + } else { + nodeFrom = process(expression.getOperands().at(0), context); + } - string ident = expression.getValueString(); - const Symbol& identSymbol = context.scope->findSymbol(ident, *man->llvm); + assert(!decl.empty()); + SymbolPacked nodeTo = clasp->pack(context.scope->findSymbol(decl)); + __context.graph.addLink(move(nodeTo), move(*nodeFrom), DFGConnection::PROTO); + } - SymbolPacked nodeFrom = __context.graph.pack(identSymbol); - if (!decl.empty()) { - SymbolPacked nodeTo = __context.graph.pack(context.scope->findSymbol(decl, *man->llvm)); - __context.graph.addLink(move(nodeTo), move(nodeFrom), DFGConnection::STRONG); - } + if (__signatures.count(expression.op) || expression.op == Operator::MAP) { + for (CodeScope* scope: expression.blocks) { + AbstractPass::process(scope, context); + } - return nodeFrom; - } + return boost::none; + } AbstractPass::process(expression, context, decl); - return SYMBOL_INVALID; + return boost::none; } void DFGPass::run() { init(); return AbstractPass::run(); } -void -DFGPass::process(const Expression& expression, PassContext context, const std::string& decl) -{ - processExpression(expression, context, decl); -} - - void DFGPass::init() { for (const Expression& scheme: man->root->__dfadata) { - __schemes.emplace(scheme.op, scheme); + __signatures.emplace(scheme.op, scheme); } } void DFGPass::finish() { man->clasp->addDFAData(move(__context.graph)); -} \ No newline at end of file +} diff --git a/cpp/src/pass/dfgpass.h b/cpp/src/pass/dfgpass.h index 3d06d8b..8622130 100644 --- a/cpp/src/pass/dfgpass.h +++ b/cpp/src/pass/dfgpass.h @@ -1,32 +1,34 @@ // Data Flow Graph determination pass #ifndef DFGPASS_H #define DFGPASS_H #include "abstractpass.h" #include "clasplayer.h" +#include namespace xreate { -class DFGPass: public AbstractPass { +typedef boost::optional SymbolPackedOptional; +class DFGPass : public AbstractPass { public: - void process(const Expression& expression, PassContext context, const std::string& varDecl=""); - SymbolPacked processExpression(const Expression& expression, PassContext context, const std::string& decl=""); + SymbolPackedOptional process(const Expression& expression, PassContext context, const std::string& varDecl="") override; DFGPass(PassManager* manager); unsigned int hash(const CodeScope* scope); void init(); void run(); void finish(); private: struct { - DFGraph graph; + DFAGraph graph; } __context; - std::map __schemes; + std::map __signatures; //DFA data for particular operators + ClaspLayer* clasp; }; }; -#endif \ No newline at end of file +#endif diff --git a/cpp/src/pass/functiontagspass.cpp b/cpp/src/pass/functiontagspass.cpp index 6242d55..6c30b77 100644 --- a/cpp/src/pass/functiontagspass.cpp +++ b/cpp/src/pass/functiontagspass.cpp @@ -1,21 +1,10 @@ -/* + #include "functiontagspass.h" -#include using namespace std; using namespace xreate; -FunctionTagsPass::FunctionTagsPass(AST& root) - : __root(root) -{ -} - void -FunctionTagsPass::run(ClaspLayer& clasp) +FunctionTagsPass::process(ManagedFnPtr function) { - for (ManagedFnPtr id=0, count = __root.getFunctionsCount(); id < count; ++id) - { - const Function& f = __root.getFunctionById(id); - clasp.addFunctionTags(f.getName(), f.getAnnotations()); - } + man->clasp->addFunctionTags(function->getName(), function->getAnnotations()); } -*/ \ No newline at end of file diff --git a/cpp/src/pass/functiontagspass.h b/cpp/src/pass/functiontagspass.h index 17b4d53..5d92786 100644 --- a/cpp/src/pass/functiontagspass.h +++ b/cpp/src/pass/functiontagspass.h @@ -1,18 +1,14 @@ #ifndef FUNCTIONTAGSPASS_H #define FUNCTIONTAGSPASS_H -#include "ast.h" -#include -#include "clasplayer.h" +#include "abstractpass.h" namespace xreate { -class FunctionTagsPass +class FunctionTagsPass: public AbstractPass { public: - FunctionTagsPass(AST& root); - void run(ClaspLayer& clasp); -private: - const AST& __root; + FunctionTagsPass(PassManager *manager): AbstractPass(manager) {} + void process(ManagedFnPtr function) override; };} #endif // FUNCTIONTAGSPASS_H diff --git a/cpp/src/pass/logging.cpp b/cpp/src/pass/logging.cpp new file mode 100644 index 0000000..0daaf05 --- /dev/null +++ b/cpp/src/pass/logging.cpp @@ -0,0 +1,106 @@ +/* + * logging.cpp + * + * Created on: Jun 23, 2015 + * Author: pgess + */ + +#include "logging.h" +#include "instructions/instr-containers.h" +#include "utils.h" + +using namespace std; +using namespace llvm; +namespace xreate { + + +void Logging::init(ClaspLayer* clasp){ + auto model = clasp->query(Config::get("logging.id")); + if(!model) return; + + for (ClaspLayer::ModelIterator rec = model->first; rec!=model->second; ++rec){ + std::tuple _v =ClaspLayer::parse(rec->second); + Symbol v = clasp->unpack(get<0>(_v)); + + SymbolAttachments::put(v, true); + } +} + +void +Logging::process(const Expression& expression, PassContext context, const std::string& varDecl){ + if (varDecl.size()){ + Symbol v = context.scope->findSymbol(varDecl); + if (SymbolAttachments::get(v, false)){ + CompilePass::FunctionUnit* f = compiler->getFunctionUnit(CompilePass::FunctionQuery(string(context.function->getName()))); + CompilePass::CodeScopeUnit* u = f->getScopeUnit(context.scope); + + CompilePass::Context compilation{f, u, compiler}; + inject(v, compilation); + } + } + + return AbstractPass::process(expression, context, varDecl); +} + +void Logging::inject(const Symbol& symbol, const CompilePass::Context& context){ + llvm::Value* source = context.scope->compileSymbol(symbol); + ExpandedType typSource = man->root->expandType(CodeScope::findDefinition(symbol)); + string format = ""; + switch (typSource->__value) { + case TypePrimitive::Int : case TypePrimitive::Num : case TypePrimitive::I32: case TypePrimitive::I8: + format = "%d\n"; + break; + + case TypePrimitive::String: + format = "%s\n"; + break; + + default: + assert(false && "No appropriate type for logging"); + } + + containers::Instructions compiler(context); + + LLVMLayer* llvm = context.pass->man->llvm; + llvm->builder.SetInsertPoint(*source->use_begin()); + llvm::Value* formatRaw = compiler.compileConstantStringAsPChar(format, "logformat"); + + llvm->builder.CreateCall2(refPrintf, formatRaw, source); +} + +void +Logging::initOutput(){ + LLVMLayer* llvm = man->llvm; + refPrintf = llvm->module->getFunction("printf"); + + if (!refPrintf) { + PointerType* typPtrI8 = PointerType::get(IntegerType::get(llvm->module->getContext(), 8), 0); + std::vectorargsPrintf{typPtrI8}; + FunctionType* signaturePrintf = FunctionType::get( + /*Result=*/IntegerType::get(llvm->module->getContext(), 32), + /*Params=*/argsPrintf, + /*isVarArg=*/true); + + refPrintf = llvm::Function::Create( + /*Type=*/signaturePrintf, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"printf", llvm->module); // (external, no body) + + refPrintf->setCallingConv(CallingConv::C); + } +} + +Logging::Logging(PassManager* manager) + : AbstractPass(manager) +{ + initOutput(); + init(man->clasp); +} + +void +Logging::initDependencies(CompilePass* pass){ + compiler = pass; +} + + +} /* namespace xreate */ diff --git a/cpp/src/pass/logging.h b/cpp/src/pass/logging.h new file mode 100644 index 0000000..4745a06 --- /dev/null +++ b/cpp/src/pass/logging.h @@ -0,0 +1,44 @@ +/* + * logging.h + * + * Created on: Jun 23, 2015 + * Author: pgess + */ + +#ifndef SRC_LOGGING_H_ +#define SRC_LOGGING_H_ + +#include "ast.h" +#include +#include "pass/compilepass.h" +#include "pass/abstractpass.h" +#include "clasplayer.h" + +namespace xreate { + +class Logging:public AbstractPass, public IQuery { +public: + void inject(const Symbol& symbol, const CompilePass::Context& context); + Logging(PassManager* manager); + + virtual void init(ClaspLayer* clasp); + void initDependencies(CompilePass* pass); + virtual void process(const Expression& expression, PassContext context, const std::string& varDecl=""); + +private: + CompilePass* compiler = nullptr; + llvm::Function* refPrintf; + void initOutput(); +}; + +struct IsLogging{}; + +template<> +struct AttachmentsDict { + typedef bool Data; + static const unsigned int key = 5; +}; + +} /* namespace xreate */ + +#endif /* SRC_LOGGING_H_ */ diff --git a/cpp/src/passmanager.cpp b/cpp/src/passmanager.cpp index 5693aaf..37c3f28 100644 --- a/cpp/src/passmanager.cpp +++ b/cpp/src/passmanager.cpp @@ -1,25 +1,84 @@ #include #include "query/containers.h" #include "passmanager.h" +#include "pass/compilepass.h" + +#include "Parser.h" +#include "pass/dfgpass.h" +#include "pass/functiontagspass.h" +#include "pass/logging.h" + using namespace xreate; using namespace std; +PassManager* +PassManager::prepareForCode(std::string&& code){ + Scanner scanner(reinterpret_cast(code.c_str()), code.size()); + return prepareForCode(scanner); +} + +PassManager* +PassManager::prepareForCode(Scanner& scanner){ + Parser parser(&scanner); + parser.Parse(); + assert(!parser.errors->count && "Parser errors"); + + PassManager* man = new PassManager; + AST* ast = new AST(parser.root); + + man->root = ast; + man->clasp = new ClaspLayer(); + + man->clasp->ast = man->root; + man->llvm = new LLVMLayer(man->root); + man->registerPass(new DFGPass(man)); + man->registerPass(new FunctionTagsPass(man)); + + return man; +} + + + void -PassManager::registerPass(AbstractPass* pass) +PassManager::registerPass(AbstractPassBase* pass) { __passes.push_back(pass); } -void +void* PassManager::run() { - for (AbstractPass* pass: __passes) + for (AbstractPassBase* pass: __passes) + { + pass->run(); + pass->finish(); + } + + clasp->registerdQuery(new containers::Query()); + clasp->run(); + + CompilePass* compiler = new CompilePass(this); + compiler->run(); + + //Compiler Dependents: + Logging* logger = new Logging(this); + logger->initDependencies(compiler); + logger->run(); + + llvm->print(); + llvm->initJit(); + return llvm->getFunctionPointer(compiler->getEntryFunction()); +} + +void PassManager::runWithoutCompilation(){ + for (AbstractPassBase* pass: __passes) { pass->run(); pass->finish(); } clasp->registerdQuery(new containers::Query()); + clasp->run(); } PassManager::~PassManager(){} diff --git a/cpp/src/passmanager.h b/cpp/src/passmanager.h index 4875ee7..e9d581c 100644 --- a/cpp/src/passmanager.h +++ b/cpp/src/passmanager.h @@ -1,27 +1,31 @@ #ifndef PASSMANAGER_H #define PASSMANAGER_H #include "clasplayer.h" #include "ast.h" #include - +#include "Scanner.h" namespace xreate { -class AbstractPass; +class AbstractPassBase; + class PassManager { public: ~PassManager(); - void run(); - void registerPass(AbstractPass* pass); + void* run(); + void runWithoutCompilation(); + void registerPass(AbstractPassBase* pass); + static PassManager* prepareForCode(std::string&& code); + static PassManager* prepareForCode(Scanner& scanner); ClaspLayer* clasp; LLVMLayer* llvm; AST* root; private: //typedef std::multimap FILTERS_STORAGE; //FILTERS_STORAGE __filters; - std::list __passes; + std::list __passes; }; } -#endif \ No newline at end of file +#endif diff --git a/cpp/src/query/containers.cpp b/cpp/src/query/containers.cpp index c317bbd..0881b47 100644 --- a/cpp/src/query/containers.cpp +++ b/cpp/src/query/containers.cpp @@ -1,155 +1,161 @@ // // Created by pgess on 3/14/15. // #include #include "query/containers.h" using namespace std; using namespace xreate::containers; using namespace xreate; -const std::string ID_IMPLEMENTATIONS = "impl_fulfill_cluster"; -const std::string ID_CLUSTERS = "var_cluster"; -const std::string ID_PROTOTYPES = "proto_cluster"; -ImplementationData + +Implementation Query::queryImplementation(xreate::Symbol const &s) { - typedef SymbolAttachments attachs; - if (attachs::exists(s)) + typedef SymbolAttachments attach; + if (attach::exists(s)) { - return SymbolAttachments::get(s); + return attach::get(s); } - return ImplementationData(s); + return Implementation::create(s); } void Query::init(ClaspLayer* clasp) { if (flagIsDataLoaded) return; map prototypes; map roots; //read all proto data - auto range = clasp->query(ID_PROTOTYPES); - for(ClaspLayer::ModelIterator atom = range.first; atom != range.second; ++atom) { + auto range = clasp->query(Config::get("containers.id.prototypes")); + if (range) + for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto data = ClaspLayer::parse(atom->second); - Symbol root = clasp->dfgData.unpack(get<0> (data)); - Symbol prototype = clasp->dfgData.unpack(get<1> (data)); + Symbol root = clasp->unpack(get<0> (data)); + Symbol prototype = clasp->unpack(get<1> (data)); prototypes[root] = prototype; } // fill implementation data for a data sources: - range = clasp->query(ID_IMPLEMENTATIONS); - for(ClaspLayer::ModelIterator atom = range.first; atom != range.second; ++atom) + range = clasp->query(Config::get("containers.id.implementations")); + if (range) + for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto data = ClaspLayer::parse(atom->second); - Symbol var = clasp->dfgData.unpack(get<0>(data)); + Symbol var = clasp->unpack(get<0>(data)); string implSerialized = get<1>(data); //data source, has no prototypes: if (!prototypes.count(var)) { - ImplementationData impl(var); - SymbolAttachments::put(var, move(impl)); + Implementation impl = Implementation::create(var); + SymbolAttachments::put(var, move(impl)); continue; } roots.emplace(move(var), move(implSerialized)); } - //fill implementation dara for a cluster roots + //fill implementation data for a cluster roots for (const pair & root: roots) { Symbol prototype = prototypes[root.first]; while (prototypes.count(prototype)) { prototype = prototypes.at(prototype); } - ImplementationData impl(root.first, root.second, SymbolAttachments::get(prototype)); - SymbolAttachments::put(root.first, move(impl)); + SymbolAttachments::put(root.first, Implementation(SymbolAttachments::get(prototype))); } // read cluster data and fill implementation data for cluster members - range = clasp->query(ID_CLUSTERS); - for(ClaspLayer::ModelIterator atom = range.first; atom != range.second; ++atom) + range = clasp->query(Config::get("containers.id.clusters")); + if (range) + for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto info = ClaspLayer::parse(atom->second); - Symbol root = clasp->dfgData.unpack(get<0>(info)); - Symbol child = clasp->dfgData.unpack(get<1>(info)); + Symbol root = clasp->unpack(get<0>(info)); + Symbol child = clasp->unpack(get<1>(info)); if (!(child == root)) { - ImplementationData rootImpl = SymbolAttachments::get(root); - SymbolAttachments::put(child, move(rootImpl)); + Implementation rootImpl = SymbolAttachments::get(root); + SymbolAttachments::put(child, move(rootImpl)); } - } flagIsDataLoaded = true; } -ImplementationData::ImplementationData(Symbol var) -{ +//static ImplementationData* create(Symbol var, std::string implSerialized, const ImplementationData* implPrototype); +Implementation +Implementation::create(const Symbol &var) +{ Expression varDecl = CodeScope::findDeclaration(var); switch (varDecl.op) { - case Operator::LIST_RANGE: - range=var; - impl = ON_THE_FLY; - break; - - case Operator::LIST: - impl = LLVM_CONST_ARRAY; - size = varDecl.getOperands().size(); - break; - - default: - assert(false && "unable to determine proper implementation for the symbol"); - break; + case Operator::LIST_RANGE: { + ImplementationRec rec{var}; + return {ON_THE_FLY, rec}; + } + + case Operator::LIST: { + return {SOLID, ImplementationRec {varDecl.getOperands().size()}}; + } }; + + ImplementationLinkedList ill(var); + if (ill){ + return ill.getImplementationData(); + } + + assert(false && "Unable to determine proper implementation for the symbol"); } -ImplementationData::ImplementationData(Symbol var, std::string implSerialized, const ImplementationData& implPrototype) +Implementation +Implementation::create(const Symbol& var, const std::string& implSerialized) { - if (implSerialized == "llvm_array") + Expression varDecl = CodeScope::findDeclaration(var); + if (implSerialized == Config::get("containers.impl.solid")) { - impl = LLVM_ARRAY; - size = implPrototype.size; - - } else if (implSerialized == "llvm_const_array") { - impl = LLVM_CONST_ARRAY; - size = implPrototype.size; + return {SOLID, ImplementationRec{varDecl.operands.size()}}; - } else if (implSerialized == "on_the_fly") { - impl = ON_THE_FLY; - range = implPrototype.range; - - } else { - assert(false && "unable to determine proper implementation for the symbol"); + } else if (implSerialized == Config::get("containers.impl.onthefly")) { + return {ON_THE_FLY, ImplementationRec{var}}; } + + assert(false && "unable to determine proper implementation for the symbol"); } -std::pair -ImplementationData::getRange() -{ - switch (impl) { - case ON_THE_FLY: { - Expression decl = CodeScope::findDeclaration(range); - assert(decl.getOperands().size() == 2); - return make_pair(decl.getOperands()[0], decl.getOperands()[1]); - } +ImplementationLinkedList::ImplementationLinkedList(const Symbol& source) + : flagIsValid(false), s(source){ - default: { - return make_pair(Expression(Atom(0)), Expression(Atom(size - 1))); - } - }; + const Expression& sourceExpr = CodeScope::findDeclaration(source); + + if (sourceExpr.tags.count(Config::get("containers.id.linkedlist"))){ + flagIsValid = true; + + Expression tagLinkedlist = sourceExpr.tags.at(Config::get("containers.id.linkedlist")); + assert(tagLinkedlist.operands.size() == 2); + fieldPointer = tagLinkedlist.operands.at(0).getValueString(); + terminator = tagLinkedlist.operands.at(1); + } +} + +ImplementationLinkedList:: operator bool () const{ + return flagIsValid; +} + +Implementation +ImplementationLinkedList::getImplementationData() const { + return {ON_THE_FLY, ImplementationRec{s}}; } diff --git a/cpp/src/query/containers.h b/cpp/src/query/containers.h index d91a89d..6da2c5e 100644 --- a/cpp/src/query/containers.h +++ b/cpp/src/query/containers.h @@ -1,49 +1,80 @@ // // Created by pgess on 3/14/15. // #ifndef _XREATE_CONTAINERSQUERY_H_ #define _XREATE_CONTAINERSQUERY_H_ #include "passmanager.h" +#include namespace xreate { namespace containers { - enum Implementation{ - LLVM_ARRAY, LLVM_CONST_ARRAY, ON_THE_FLY + enum ImplementationType {SOLID, ON_THE_FLY, LINKED_LIST}; + + template + struct ImplementationRec; + + template<> + struct ImplementationRec { + size_t size; + }; + + template<> + struct ImplementationRec{ + Symbol source; + }; + + struct Implementation; + struct ImplementationLinkedList { + bool flagIsValid; + std::string fieldPointer; + Expression terminator; + + ImplementationLinkedList(const Symbol& source); + operator bool() const; + Implementation getImplementationData() const; + + private: + Symbol s; }; - struct ImplementationData { - Implementation impl; - union { - unsigned int size; //valid in case of LLVM_ARRAY impl. - struct { - Symbol range; - }; - }; - ImplementationData(Symbol var); - ImplementationData(Symbol var, std::string implSerialized, const ImplementationData& implPrototype); - std::pair getRange(); + struct Implementation { + typedef boost::variant, ImplementationRec> Variant; + const ImplementationType impl; + Variant data; + + static Implementation create(const Symbol &var); + static Implementation create(const Symbol& var, const std::string &implSerialized); + static Implementation create(const Symbol& var, const Implementation& proto); + + template + const ImplementationRec& extract() const{ + const ImplementationRec& rec = boost::get>(data); + return rec; + } }; class Query : public xreate::IQuery { public: - static ImplementationData queryImplementation(xreate::Symbol const &s); + static Implementation queryImplementation(xreate::Symbol const &s); void init(ClaspLayer* clasp); ~Query(){} private: bool flagIsDataLoaded = false; PassManager *man; }; + + } - template<> - struct AttachmentsDictionary { - typedef containers::ImplementationData Data; + template<> + struct AttachmentsDict { + typedef containers::Implementation Data; static const unsigned int key = 1; }; } #endif //_XREATE_CONTAINERSQUERY_H_ diff --git a/cpp/src/query/ptrvalid.cpp b/cpp/src/query/ptrvalid.cpp new file mode 100644 index 0000000..ff31d76 --- /dev/null +++ b/cpp/src/query/ptrvalid.cpp @@ -0,0 +1,15 @@ +/* + * QueryPtrValid.cpp + * + * Created on: Jun 17, 2015 + * Author: pgess + */ + +#include + +using namespace xreate; + +bool +QueryPtrValid::assertValidPtr(const Symbol& s) { + return false; +} diff --git a/cpp/src/query/ptrvalid.h b/cpp/src/query/ptrvalid.h new file mode 100644 index 0000000..02794c5 --- /dev/null +++ b/cpp/src/query/ptrvalid.h @@ -0,0 +1,24 @@ +/* + * QueryPtrValid.h + * + * Created on: Jun 17, 2015 + * Author: pgess + */ + +#ifndef SRC_QUERY_PTRVALID_H_ +#define SRC_QUERY_PTRVALID_H_ + +#include + +namespace xreate { + +class QueryPtrValid: public xreate::IQuery { +public: + QueryPtrValid(); + virtual void init(ClaspLayer* clasp); + + static bool assertValidPtr(const Symbol& s); +}; + +} +#endif /* SRC_QUERY_PTRVALID_H_ */ diff --git a/cpp/src/utils.cpp b/cpp/src/utils.cpp new file mode 100644 index 0000000..693a00e --- /dev/null +++ b/cpp/src/utils.cpp @@ -0,0 +1,9 @@ +#include "utils.h" + +using namespace xreate; + +Config Config::__self = Config(); + +Config::Config() +: __storage{json_file{ "config/default.json" }} +{} diff --git a/cpp/src/utils.h b/cpp/src/utils.h index 3eb314f..532b46d 100644 --- a/cpp/src/utils.h +++ b/cpp/src/utils.h @@ -1,65 +1,128 @@ #ifndef UTILS_H #define UTILS_H -#include "ast.h" +#include "jeayeson/jeayeson.hpp" //TODO mark dirty members /* template struct DdesctructableClass { } */ /* template struct TagUpdatable{ TagUpdatable(const OriginalType& source) : __source(source) {} TagUpdatable() = delete; const OriginalType& __source; }; struct Updatable; template struct TagsDictionary {}; template struct TagsDictionary { typedef TagUpdatable TagName; }; template struct awareOf { awareOf(OT& dest) : __dest(dest) {} awareOf& operator= (const typename TagsDictionary::TagName& source) { __dest = source.__source; } private: OT& __dest; }; template> const OT& awareOf(const Tag& holder) { return std::forward(holder.__source); } -*/ + */ + +namespace xreate { + template + struct AddTag { + + explicit + AddTag(const Source &&src) + : __src(src) { } + + operator const Source&() const{ + return __src; + } + + const Source& get() const{ + return __src; + } + + const Source* + operator->() const { + return &__src; + } + + private: + Source __src; + }; + + struct Expand_t{}; + template + using Expanded = AddTag; + + + class Config { + private: + json_map __storage; + static Config __self; + Config(); + + public: + static std::string get(std::string key) { + return __self.__storage.get_for_path(key).get(); + } + }; +} + +#define RST "\x1B[0m" +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KYEL "\x1B[33m" +#define KBLU "\x1B[34m" +#define KMAG "\x1B[35m" +#define KCYN "\x1B[36m" +#define KWHT "\x1B[37m" + +#define FRED(x) KRED << x << RST +#define FGRN(x) KGRN <getEntryScope(); + Symbol symb_chilrenRaw = body->findSymbol("childrenRaw"); + + containers::ImplementationLinkedList iLL(symb_chilrenRaw); + + ASSERT_EQ(true, static_cast(iLL)); + ASSERT_EQ("next", iLL.fieldPointer); + + Implementation impl = Implementation::create(symb_chilrenRaw); + ASSERT_NO_FATAL_FAILURE(impl.extract()); + + ImplementationRec recOnthefly = impl.extract(); + ASSERT_EQ(symb_chilrenRaw, recOnthefly.source); +} + +TEST(Containers, Implementation_LinkedListFull){ + FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); + assert(input != nullptr); + + Scanner scanner(input); + std::unique_ptr program(PassManager::prepareForCode(scanner)); + void* mainPtr = program->run(); + int (*main)() = (int (*)())(intptr_t)mainPtr; + + int answer = main(); + ASSERT_EQ(16, answer); + + fclose(input); +} + diff --git a/cpp/tests/externc.cpp b/cpp/tests/externc.cpp new file mode 100644 index 0000000..fe5587e --- /dev/null +++ b/cpp/tests/externc.cpp @@ -0,0 +1,105 @@ +#include "gtest/gtest.h" +#include "passmanager.h" +#include "pass/functiontagspass.h" +#include "Scanner.h" +#include "Parser.h" +#include +#include + +using namespace std; + +TEST(InterfaceExternC, testAST){ + std::string code = " \ + interface(extern-c){ \ + xml2 = library:: pkgconfig(\"libxml-2.0\"). \ + \ + include { \ + xml2 = [\"libxml/tree.h\"] \ + }. \ + } \ + "; + + Scanner scanner(reinterpret_cast(code.c_str()), code.size()); + Parser parser(&scanner); + parser.Parse(); + + ASSERT_EQ(1, parser.root.__externdata.size()); + + for (const ExternEntry& lib: parser.root.__externdata){ + ASSERT_EQ("libxml-2.0", lib.package); + ASSERT_EQ(1, lib.headers.size()); + ASSERT_EQ("libxml/tree.h", lib.headers.at(0)); + } +} + +TEST(InterfaceExternC, testfetchPackageHeaders){ + ExternEntry entry{"libxml-2.0", {}}; + + vector args = ExternLayer::fetchPackageFlags(entry); + ASSERT_EQ(1, args.size()); + ASSERT_EQ("-I/usr/include/libxml2", args.at(0)); +} + +TEST(InterfaceExternC, testfetchPackageLibs){ + ExternEntry entry{"libxml-2.0", {}}; + + vector args = ExternLayer::fetchPackageLibs(entry); + ASSERT_EQ(1, args.size()); + ASSERT_EQ("-lxml2", args.at(0)); +} + +TEST(InterfaceExternC, testLoadLib){ + std::string msgErr; + if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently("-lpcre -lxml2", &msgErr)){ + cout << msgErr; + ASSERT_EQ("", msgErr); + } + + ASSERT_TRUE(true); +} + +TEST(InterfaceExternC, testBSD1){ + std::string code = " \n\ + interface(extern-c){ \n\ + libbsd = library:: pkgconfig(\"libbsd\"). \n\ + \n\ + include { \n\ + libbsd = [\"bsd/stdlib.h\"] \n\ + }. \n\ + }\n" + "main= function():: int; entry{return arc4random() }"; + + std::unique_ptr program(PassManager::prepareForCode(move(code))); + + void* entryPtr = program->run(); + int (*entry)() = (int (*)())(intptr_t)entryPtr; + + int answer = 24; + answer = entry(); + cout << answer; + ASSERT_NE(24, answer); +} + +TEST(InterfaceExternC, testStructFields1){ + FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); + assert(input != nullptr); + + Scanner scanner(input); + Parser parser(&scanner); + parser.Parse(); + + AST& ast = parser.root; + CodeScope* body = ast.findFunction("test")->getEntryScope(); + + Symbol symbTree = body->findSymbol("tree"); + + const TypeAnnotation& tTree = CodeScope::findDefinition(symbTree); + const ExpandedType& t2Tree = ast.expandType(tTree); + LLVMLayer llvm(&ast); + TypeUtils utils(&llvm); + + std::vectorfields = utils.getStructFields(t2Tree); + + auto field = std::find(fields.begin(), fields.end(), "children"); + ASSERT_TRUE(field != fields.end()); +} diff --git a/cpp/tests/safety.cpp b/cpp/tests/safety.cpp new file mode 100644 index 0000000..2af6879 --- /dev/null +++ b/cpp/tests/safety.cpp @@ -0,0 +1,9 @@ +#include "gtest/gtest.h" + +/** + * Safety checks: + * (*) valid ptr (not null) + */ +TEST(Safety, validptr1){ + +} diff --git a/cpp/tests/testBasic.cpp b/cpp/tests/testBasic.cpp new file mode 100644 index 0000000..8826b37 --- /dev/null +++ b/cpp/tests/testBasic.cpp @@ -0,0 +1,27 @@ + +#include "gtest/gtest.h" +#include "passmanager.h" +#include "pass/functiontagspass.h" +#include "Scanner.h" +#include "Parser.h" +#include +#include + +using namespace std; +using namespace xreate; + +TEST(EntryFunction, test1){ + std::unique_ptr program(PassManager::prepareForCode( + "func1 = function(a:: int):: int {a+8} \ + func2 = function()::int; entry {12 + func1(4)} \ + ")); + + void* entryPtr = program->run(); + int (*entry)() = (int (*)())(intptr_t)entryPtr; + + int answer = entry(); + ASSERT_EQ(24, answer); +} + + + diff --git a/cpp/tests/testClangAPI.cpp b/cpp/tests/testClangAPI.cpp new file mode 100644 index 0000000..d426cf1 --- /dev/null +++ b/cpp/tests/testClangAPI.cpp @@ -0,0 +1,191 @@ +// +// Created by pgess on 4/16/15. +// + +#include "gtest/gtest.h" + +#include +#include "clang/Driver/Options.h" +#include "clang/AST/AST.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Tooling.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/CodeGen/CodeGenAction.h" +#include "/private/prg/vendors/clang/lib/CodeGen/CodeGenTypes.h" +#include "/private/prg/vendors/clang/lib/CodeGen/CodeGenModule.h" +#include "clang/CodeGen/CodeGenABITypes.h" +#include "llvm/IR/LLVMContext.h" +#include "clang/Basic/TargetInfo.h" +#include + + + +using namespace std; +using namespace clang; +using namespace clang::driver; +using namespace clang::tooling; +using namespace clang::ast_matchers; +using namespace llvm; + +/* +class PrintFunctionsConsumer : public ASTConsumer { +public: + bool HandleTopLevelDecl(DeclGroupRef DG) override { + for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) { + const Decl *D = *i; + if (const NamedDecl *ND = dyn_cast(D)) + llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n"; + } + + return true; + } +}; + +class PFAction : public ASTFrontendAction { +public: + virtual std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef file) { + return llvm::make_unique(); + } +}; +*/ + +class PrinterType : public MatchFinder::MatchCallback { +public : + virtual void run(const MatchFinder::MatchResult &Result) { + ASTContext* C = Result.Context; + llvm::Module* M = new llvm::Module("module1", llvm::getGlobalContext()); + if (const TypedefDecl* decl = Result.Nodes.getNodeAs("typename")) { + QualType Ty = decl->getUnderlyingType(); + + llvm::errs() << "<" << Ty.getAsString() << ">" ; + + CodeGenOptions *CGO = new CodeGenOptions; + + const llvm::DataLayout& TD = llvm::DataLayout(C->getTargetInfo().getTargetDescription()); + CodeGen::CodeGenModule *CGM = new CodeGen::CodeGenModule(*C, *CGO, *M, TD, C->getDiagnostics()); + + llvm::Type *rawTy = CGM->getTypes().ConvertType(Ty); + + rawTy->dump(); + results.push_back(rawTy); + } + } + + std::vector results; +}; + +class PrinterFunction: public MatchFinder::MatchCallback { +public : + virtual void run(const MatchFinder::MatchResult &Result) { + if (const FunctionDecl* decl = Result.Nodes.getNodeAs("function")) { + QualType Ty = decl->getType(); + + llvm::errs() << "<" << Ty.getAsString() << ">" ; + ASTContext* C = Result.Context; + llvm::Module* M = new llvm::Module("module1", llvm::getGlobalContext()); + CodeGenOptions *CGO = new CodeGenOptions; + + const llvm::DataLayout& TD = llvm::DataLayout(C->getTargetInfo().getTargetDescription()); + CodeGen::CodeGenModule *CGM = new CodeGen::CodeGenModule(*C, *CGO, *M, TD, C->getDiagnostics()); + + llvm::Type *rawTy = CGM->getTypes().ConvertType(Ty); + + //const clang::FunctionType* Ty = decl->getType()->getAs(); + llvm::FunctionType* rawFuncTy = llvm::dyn_cast(rawTy); + rawFuncTy->dump(); + results.push_back(rawFuncTy); + + /* + llvm::Function* fDeclaration = llvm::Function::Create(rawFuncTy, llvm::GlobalValue::ExternalLinkage, "xxxx", M); + fDeclaration->dump(); + */ + } + } + + std::vector results; +}; + +vector argv = { + "-I/usr/include/libxml2" + ,"-I/usr/local/include" + ,"-I/usr/lib/llvm-3.7/bin/../lib/clang/3.7.0/include" + ,"-I/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/include" + ,"-I/usr/include/x86_64-linux-gnu" + ,"-I/usr/include" +}; + +TEST(ClangAPI, testExternalType) +{ + + //,, "-I/usr/include/linux" +// "-cc1", "-emit-pch", "-disable-free", "-disable-llvm-verifier", "-mrelocation-model", "static", +// "-mthread-model", "posix", "-mdisable-fp-elim", "-fmath-errno", "-masm-verbose", +// "-mconstructor-aliases", "-munwind-tables", "-fuse-init-array", "-target-cpu", "x86-64", "-target-linker-version", "2.25", + //"-dwarf-column-info", "-resource-dir", "/usr/lib/llvm-3.7/bin/../lib/clang/3.7.0", + //"clang", "--", + + + /* + int argc= argv.size(); + + llvm::cl::OptionCategory cat("aaaa"); + LLVMInitializeNativeTarget(); + CommonOptionsParser op(argc, &*(argv.begin()), cat); + ClangTool tool(op.getCompilations(), op.getSourcePathList()); + */ + + auto matcherType = + typedefDecl(hasName("xmlNodePtr")).bind("typename"); + + MatchFinder finder; + PrinterType printer; + finder.addMatcher(matcherType, &printer); + + std::string code = QString("#include \"%1\"").arg("libxml/tree.h").toStdString(); + //runToolOnCodeWithArgs(newFrontendActionFactory(&finder).get()->create(), code, argv); + + std::unique_ptr ast = buildASTFromCodeWithArgs(code, argv); + ASTContext & context = ast->getASTContext(); + finder.matchAST(context); + + string signatureExpected = "%struct._xmlNode.0*"; + ASSERT_EQ(1, printer.results.size()); + + llvm::Type* tyActual = printer.results.at(0); + string strActual; + llvm::raw_string_ostream ss(strActual); + tyActual->print(ss); + ASSERT_EQ(signatureExpected, ss.str()); + + //int x = tool.run(newFrontendActionFactory(&finder).get()); +} + +TEST(ClangAPI, testExternalFunction){ + auto matcherType = functionDecl(hasName("arc4random")).bind("function"); + + MatchFinder finder; + PrinterFunction printer; + finder.addMatcher(matcherType, &printer); + + std::string code = QString("#include \"%1\"").arg("bsd/stdlib.h").toStdString(); + std::unique_ptr ast = buildASTFromCodeWithArgs(code, argv); + ASTContext & context = ast->getASTContext(); + finder.matchAST(context); + + string signatureExpected = "i32 ()"; + ASSERT_EQ(1, printer.results.size()); + + llvm::Type* tyActual = printer.results.at(0); + string strActual; + llvm::raw_string_ostream ss(strActual); + tyActual->print(ss); + ASSERT_EQ(signatureExpected, ss.str()); +} diff --git a/cpp/tests/testClangAPI.h b/cpp/tests/testClangAPI.h new file mode 100644 index 0000000..aab7ee5 --- /dev/null +++ b/cpp/tests/testClangAPI.h @@ -0,0 +1,9 @@ +// +// Created by pgess on 4/16/15. +// + +#ifndef XREATE_TESTCLANGAPI_H +#define XREATE_TESTCLANGAPI_H + +void testClang1(); +#endif //XREATE_TESTCLANGAPI_H diff --git a/cpp/tests/testJson.cpp b/cpp/tests/testJson.cpp new file mode 100644 index 0000000..18e59cb --- /dev/null +++ b/cpp/tests/testJson.cpp @@ -0,0 +1,9 @@ +#include "utils.h" +#include "gtest/gtest.h" +using namespace std; +using namespace xreate; + +TEST(JSON, Test1){ + string key = Config::get("containers.id.implementations"); + EXPECT_EQ("impl_fulfill_cluster", key); +} diff --git a/cpp/tests/testLibXml2.cpp b/cpp/tests/testLibXml2.cpp new file mode 100644 index 0000000..ada2404 --- /dev/null +++ b/cpp/tests/testLibXml2.cpp @@ -0,0 +1,37 @@ +// +// Created by pgess on 3/28/15. +// +#include +#include +#include + +using namespace std; + +TEST(libxml2, ReadXML) +{ + char* docname = "project/documentation.fodt" ; + xmlDocPtr doc; + xmlNodePtr cur; + doc = xmlParseFile(docname); + if (doc == NULL ) { + fprintf(stderr,"Document not parsed successfully. \n"); + return; + } + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + fprintf(stderr,"empty document\n"); + xmlFreeDoc(doc); + return; + } + + cur = cur->xmlChildrenNode; + int count =0; + while (cur != NULL) { + printf("child: %s\n", cur->name); + + cur = cur->next; + count ++; + } + + ASSERT_EQ(17, count); +} diff --git a/cpp/tests/testLogging.cpp b/cpp/tests/testLogging.cpp new file mode 100644 index 0000000..1d6de19 --- /dev/null +++ b/cpp/tests/testLogging.cpp @@ -0,0 +1,87 @@ +/* + * testLogging.cpp + * + * Created on: Jun 23, 2015 + * Author: pgess + */ + +#include "gtest/gtest.h" +#include "passmanager.h" +#include "llvmlayer.h" +#include "Parser.h" +#include "pass/compilepass.h" +#include "pass/logging.h" + +using namespace std; +using namespace xreate; + +TEST(Logging, simpleInjection){ + PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int. return x}"); + + man->runWithoutCompilation(); + CompilePass* compilator = new CompilePass(man); + compilator->run(); + + CompilePass::FunctionUnit* fTest = compilator->getFunctionUnit(CompilePass::FunctionQuery("test")); + ASSERT_NE(fTest, nullptr); + CompilePass::CodeScopeUnit* scopeUnitTest = fTest->getEntry(); + CodeScope* scopeTest = scopeUnitTest->scope; + Symbol symbX = scopeTest->findSymbol("x"); + TypeAnnotation typX = scopeTest->findDefinition(symbX); + + llvm::Value* retRaw = scopeUnitTest->compile(); + llvm::BasicBlock& blockTestRaw = fTest->raw->getEntryBlock(); + + LLVMLayer* llvm = man->llvm; + //llvm->builder.SetInsertPoint(&blockTestRaw); + CompilePass::Context params{fTest, scopeUnitTest, compilator}; + + Logging l(man); + l.inject(symbX, params); + + + llvm->initJit(); + int (*f)() = (int(*)()) llvm->getFunctionPointer(fTest->raw); + testing::internal::CaptureStdout(); + f(); + std::string&& output = testing::internal::GetCapturedStdout(); + EXPECT_STREQ("10\n", output.c_str()); +} + +TEST(Logging, simpleInjection2){ + PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int; logging. return x}"); + + man->runWithoutCompilation(); + CompilePass* compiler= new CompilePass(man); + compiler->run(); + + Logging* logger = new Logging(man); + logger->initDependencies(compiler); + logger->run(); + + man->llvm->initJit(); + man->llvm->print(); + int (*f)() = (int(*)()) man->llvm->getFunctionPointer(compiler->getEntryFunction()); + testing::internal::CaptureStdout(); + f(); + std::string&& output = testing::internal::GetCapturedStdout(); + EXPECT_STREQ("10\n", output.c_str()); +} + +TEST(Logging, simpleInjection3){ + FILE* input = fopen("scripts/cases/log.xreate","r"); + assert(input != nullptr); + + Scanner scanner(input); + std::unique_ptr program(PassManager::prepareForCode(scanner)); + void* mainPtr = program->run(); + int (*main)() = (int (*)())(intptr_t)mainPtr; + + int answer = main(); + + fclose(input); +} + + + + diff --git a/cpp/tests/tests.cpp b/cpp/tests/tests.cpp index 81ce6e8..d0e8410 100644 --- a/cpp/tests/tests.cpp +++ b/cpp/tests/tests.cpp @@ -1,113 +1,135 @@ -#include "Scanner.h" -#include "Parser.h" -#include "ast.h" -#include -#include -#include "clasplayer.h" -#include "passmanager.h" -#include "pass/dfgpass.h" +#include "utils.h" +#include using namespace std; +using namespace xreate; -void testParser_1() -{ - shared_ptr scanner(new Scanner(L"scripts/input.xreate")); - shared_ptr parser(new Parser(scanner.get())); - parser->Parse(); - flush(cout); +int main(int argc, char **argv) { + testing::GTEST_FLAG(color) = "yes"; - AST& root = parser->root; - LLVMLayer l; - - root.compile(l); - root.run(l); -} - -void testClasp2() -{ - shared_ptr scanner(new Scanner(L"scripts/input.xreate")); - shared_ptr parser(new Parser(scanner.get())); - parser->Parse(); - flush(cout); - - if (parser->errors->count) - { - cout << "Found " << parser->errors->count << " errors. Stop" << endl; - exit(1); - } - - AST& root = parser->root; - ClaspLayer clasp; - - /* - FunctionTagsPass(root).run(clasp); - RulesPass(root).run(clasp); - - CFGPass(&clasp).run(); - - clasp.1 - run(); - */ + string testsTemplate = Config::get("tests.template"); + string testsFilter = Config::get(string("tests.templates.") + testsTemplate); + testing::GTEST_FLAG(filter) = testsFilter; + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } -void testUnsafeCode1() -{ - shared_ptr scanner(new Scanner(L"scripts/cases/bugs-code.xreate")); - shared_ptr parser(new Parser(scanner.get())); - parser->Parse(); - flush(cout); - - if (parser->errors->count) - { - cout << "Found " << parser->errors->count << " errors. Stop" << endl; - exit(1); - } - - AST& root = parser->root; - ClaspLayer clasp; - - /* - FunctionTagsPass(root).run(clasp); - RulesPass(root).run(clasp); - - CFGPass(&clasp).run(); - //clasp.addRule(":- call(X, Y), tag(Y, unsafe), not tag(X, unsafe), function(X), function(Y)."); - clasp.run(); - */ -} - -void test_DFG_1() -{ - shared_ptr scanner(new Scanner(L"scripts/input.xreate")); - shared_ptr parser(new Parser(scanner.get())); - parser->Parse(); - flush(cout); - - if (parser->errors->count) - { - cout << "Found " << parser->errors->count << " errors. Stop" << endl; - exit(1); - } - - PassManager m; - m.clasp = new ClaspLayer(); - - m.llvm = new LLVMLayer(); - m.root = & parser->root; - m.clasp->ast = m.root; - - m.registerPass(new DFGPass(&m)); - m.run(); - - m.clasp->run(); - m.root->compile(*m.llvm); - m.root->run(*m.llvm); -} - -int main() -{ - test_DFG_1(); - - return 0; -} +//void testParser_1() +//{ +// shared_ptr scanner(new Scanner(L"scripts/input.xreate")); +// shared_ptr parser(new Parser(scanner.get())); +// parser->Parse(); +// flush(cout); + +// AST& root = parser->root; +// LLVMLayer l(&root); + +// root.compile(l); +// root.run(l); +//} + +//void testClasp2() +//{ +// shared_ptr scanner(new Scanner(L"scripts/input.xreate")); +// shared_ptr parser(new Parser(scanner.get())); +// parser->Parse(); +// flush(cout); + +// if (parser->errors->count) +// { +// cout << "Found " << parser->errors->count << " errors. Stop" << endl; +// exit(1); +// } + +// AST& root = parser->root; +// ClaspLayer clasp; + +// /* +// FunctionTagsPass(root).run(clasp); +// RulesPass(root).run(clasp); + +// CFGPass(&clasp).run(); + +// clasp.1 +// run(); +// */ +//} + +//void testUnsafeCode1() +//{ +// shared_ptr scanner(new Scanner(L"scripts/cases/bugs-code.xreate")); +// shared_ptr parser(new Parser(scanner.get())); +// parser->Parse(); +// flush(cout); + +// if (parser->errors->count) +// { +// cout << "Found " << parser->errors->count << " errors. Stop" << endl; +// exit(1); +// } + +// AST& root = parser->root; +// ClaspLayer clasp; + +// /* +// FunctionTagsPass(root).run(clasp); +// RulesPass(root).run(clasp); + +// CFGPass(&clasp).run(); +// //clasp.addRule(":- call(X, Y), tag(Y, unsafe), not tag(X, unsafe), function(X), function(Y)."); + +// clasp.run(); +// */ +//} + +//void test_DFG_1() +//{ +// shared_ptr scanner(new Scanner(L"scripts/input.xreate")); +// shared_ptr parser(new Parser(scanner.get())); +// parser->Parse(); +// flush(cout); + +// if (parser->errors->count) +// { +// cout << "Found " << parser->errors->count << " errors. Stop" << endl; +// exit(1); +// } + +// PassManager m; +// m.clasp = new ClaspLayer(); + +// m.llvm = new LLVMLayer(&parser->root); +// m.root = & parser->root; +// m.clasp->ast = m.root; + +// m.registerPass(new DFAPass(&m)); +// m.run(); + +// m.clasp->run(); +// m.root->compile(*m.llvm); +// m.root->run(*m.llvm); +//} + +//void test_Xml_1() +//{ +// shared_ptr scanner(new Scanner(L"scripts/input.xreate")); +// shared_ptr parser(new Parser(scanner.get())); +// parser->Parse(); +// flush(cout); + +// if (parser->errors->count) +// { +// cout << "Found " << parser->errors->count << " errors. Stop" << endl; +// exit(1); +// } + +// PassManager m; +// m.root = & parser->root; +// m.clasp = new ClaspLayer(); +// m.clasp->ast = m.root; +// m.llvm = new LLVMLayer(&parser->root); + +// m.registerPass(new DFAPass(&m)); +// m.run(); +//} diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp new file mode 100644 index 0000000..1f63042 --- /dev/null +++ b/cpp/tests/types.cpp @@ -0,0 +1,129 @@ +/* + * types.cpp + * + * Created on: Jun 4, 2015 + * Author: pgess + */ + +#include "gtest/gtest.h" +#include "passmanager.h" +#include "llvmlayer.h" +#include "Parser.h" + +using namespace std; +using namespace xreate; + +TEST(Types, DependantTypes1) { + string&& code = "XmlNode = type alias {\n" + " tag:: string,\n" + " /* attrs:: [string],*/\n" + " content:: string\n" + "}.\n"; + + std::unique_ptr program(PassManager::prepareForCode(move(code))); + ExpandedType typeXmlNode = program->root->findType("XmlNode"); + + ASSERT_EQ(TypeOperator::STRUCT, typeXmlNode->__operator); + ASSERT_EQ(2, typeXmlNode->__operands.size()); + ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); + ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(1).__value); +} + +TEST(Types, DependantTypes2) { + string&& code = "XmlNode = type alias {\n" + " tag:: string,\n" + " /* attrs:: [string],*/\n" + " content:: string\n" + "}.\n" + "" + "Template = type Template(Leaf) [Leaf, [Leaf[content]]]." + "Concrete = type alias Template(XmlNode)."; + + std::unique_ptr program(PassManager::prepareForCode(move(code))); + ExpandedType typeConcrete = program->root->findType("Concrete"); + + + ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); + ASSERT_EQ(2, typeConcrete->__operands.size()); + ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); + + ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); + ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value); +} + +TEST(Types, TreeType1) { + string&& code = "XmlNode = type alias {\n" + " tag:: string,\n" + " /* attrs:: [string],*/\n" + " content:: string\n" + "}.\n" + "" + "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." + "Concrete = type alias Tree(XmlNode)."; + + std::unique_ptr program(PassManager::prepareForCode(move(code))); + ExpandedType typeConcrete = program->root->findType("Concrete"); + + ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); + ASSERT_EQ(2, typeConcrete->__operands.size()); + ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); + + ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); + + auto typeLink = typeConcrete->__operands.at(1).__operands.at(0); + ASSERT_EQ(TypeOperator::LINK, typeLink.__operator); + ASSERT_EQ(typeConcrete->conjuctionId,typeLink.conjuctionId); +} + +TEST(Types, TreeType1LLvm){ + string&& code = "XmlNode = type alias {\n" + " tag:: string,\n" + " /* attrs:: [string],*/\n" + " content:: string\n" + "}.\n" + "" + "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." + "Concrete = type alias Tree(XmlNode)."; + + std::unique_ptr program(PassManager::prepareForCode(move(code))); + ExpandedType typeConcrete = program->root->findType("Concrete"); + + llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); +} + +TEST(Types, ArrayOfExternal1){ + FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); + assert(input != nullptr); + + Scanner scanner(input); + Parser parser(&scanner); + parser.Parse(); + + AST& ast = parser.root; + CodeScope* body = ast.findFunction("test")->getEntryScope(); + + Symbol symb = body->findSymbol("childrenRaw"); + + const TypeAnnotation& t = CodeScope::findDefinition(symb); + const ExpandedType& t2 = ast.expandType(t); + EXPECT_EQ(t2->__operator, TypeOperator::ARRAY); +} + +TEST(Types, ExternType1){ + FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); + assert(input != nullptr); + + Scanner scanner(input); + Parser parser(&scanner); + parser.Parse(); + + AST& ast = parser.root; + CodeScope* body = ast.findFunction("test")->getEntryScope(); + + Symbol symbTree = body->findSymbol("tree"); + + const TypeAnnotation& t = CodeScope::findDefinition(symbTree); + const ExpandedType& t2 = ast.expandType(t); + EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM); +} + diff --git a/scripts/input.xreate b/scripts/cases/containers.xreate similarity index 57% copy from scripts/input.xreate copy to scripts/cases/containers.xreate index d588ab6..31ecddf 100644 --- a/scripts/input.xreate +++ b/scripts/cases/containers.xreate @@ -1,28 +1,36 @@ +/* + * + * Show-case for a automatic adjustment of container implementations based on actual operations. + * Possible implementations: llvm_array, llvm_const_array, on_the_fly(unwinded container) + * + */ + pass(dfa) { - operator map: (op(seqaccess)) -> impl(llvm_array); + operator map: (op(seqaccess)) -> impl(solid); operator list_range: ()->impl(on_the_fly); - operator list: ()->impl(llvm_const_array); + operator list: ()->impl(solid); operator fold: (op(seqaccess)); operator index: (op(randaccess)); /* operator map: (op(seqaccess)) -> impl(llvm_array | on_the_fly); */ } import raw("core/containers.lp"); -testfunc4 = function: ()->bool +testfunc = function: ()->bool { a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] : [num]; a2 = [1 .. 100] : [num]; b = loop map (a1 -> el: num) : [num] - {2 * el;}; + {2 * el;}; c = b : [num]; d = loop fold (a2->el: num, 0->acc: num): [num] {acc + el;}; c[5]==d; } + diff --git a/scripts/cases/log.xreate b/scripts/cases/log.xreate new file mode 100644 index 0000000..1bb0ac9 --- /dev/null +++ b/scripts/cases/log.xreate @@ -0,0 +1,64 @@ +/* + + Log level: + Log entry(flat, hierarchical) + +*/ + + + + + // EXTERN INCLUDES +interface(extern-c){ + xml2 = library:: pkgconfig("libxml-2.0"). + + include { + xml2 = ["libxml/tree.h", "string.h"] + }. +} + + // CONTAINERS +interface(dfa) { + operator map:: (op(seqaccess)) -> impl(solid). + operator list_range:: ()->impl(on_the_fly). + operator list:: ()->impl(solid). + operator fold:: (op(seqaccess)). + operator index:: (op(randaccess)). + /* operator map: (op(seqaccess)) -> impl(llvm_array | on_the_fly); */ +} + +import raw("core/containers.lp"). + + + // PROGRAM +XmlNode = type alias { + tag:: string, + /* attrs:: [string],*/ + content:: string +}. + +Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]. +XmlTree = type alias Tree(XmlNode). + + +test= function():: num; entry { + filename = "project/documentation.fodt" :: string. + docRaw = xmlParseFile(filename) :: xmlDocPtr. + tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr. + childrenRaw = tree["children"]:: [xmlNodePtr]; containers:linkedlist(next, null). + size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count::int):: int { + +// $log{ +// count +1:: warning, subsystem=xml +// } + + + //log{warning, subsystem=xml, ..} + childName = child["name"]::string; logging. + count + strlen(childName):: int + }. + + size +} + + diff --git a/scripts/containers-set-intersection.xreate b/scripts/containers-set-intersection.xreate new file mode 100644 index 0000000..22b378d --- /dev/null +++ b/scripts/containers-set-intersection.xreate @@ -0,0 +1,11 @@ +/** + * intersection of two sets + */ + +intersection = function(X: [a], sorted; Y: [b], sorted) +{ + loop map (X -> x: a | exists(Y, x)) + {x;}; +} + + \ No newline at end of file diff --git a/scripts/ftransform.li b/scripts/ftransform.li deleted file mode 100644 index d75c454..0000000 --- a/scripts/ftransform.li +++ /dev/null @@ -1,26 +0,0 @@ -//преобразование параметров функции - -function(first-function, vars-list(var(x, i32), var(y, i32)), i32, - div(add(x, 5), y)) - --------------------------------------------------------------------------------------------------- - -type(name(ListNode), struct( - field(name(caption), type(String)), - field(name(args), type(collection(ListNode))) -)) - - - -transform( - name(f-transform), guard(var(name(X), constraints(caption(simple-function)))), - body( - set (args, field(X, args), - - - wrap(extract(args, 0), caption(name)), - - wrap - name(field()) - ) -) diff --git a/scripts/input.xreate b/scripts/input.xreate index d588ab6..ccb0330 100644 --- a/scripts/input.xreate +++ b/scripts/input.xreate @@ -1,28 +1,92 @@ -pass(dfa) { - operator map: (op(seqaccess)) -> impl(llvm_array); - operator list_range: ()->impl(on_the_fly); - operator list: ()->impl(llvm_const_array); - operator fold: (op(seqaccess)); - operator index: (op(randaccess)); - /* operator map: (op(seqaccess)) -> impl(llvm_array | on_the_fly); */ + + +/* local scope doc ptr */ + + +XmlNode = type alias { + tag:: string, + /* attrs:: [string],*/ + content:: string +}. + +interface(extern-c){ + xml2 = library:: pkgconfig("libxml-2.0"). + + include { + xml2 = ["libxml/tree.h"] + }. +} + +Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]. +XmlTree = type alias Tree(XmlNode). + + +test= function():: num; entry { + filename = "project/documentation.fodt" :: string. + docRaw = xmlParseFile(filename) :: xmlDocPtr. + tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr. + childrenRaw = tree["xmlChildrenNode"]:: [xmlNodePtr]; containers:linkedlist(next, null). + size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count::int) : int { + count +1 + }. + + size } -import raw("core/containers.lp"); +/* +toXmlNode = function (nodeRaw:: xmlNodePtr):: XmlNode +{ + {tag = nodeRaw["name"], content=null} +} -testfunc4 = function: ()->bool +children = function (tree:: xmlNodePtr):: XmlTree { - a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] : [num]; - a2 = [1 .. 100] : [num]; + childrenRaw = tree["xmlChildrenNode"]:: [xmlNodePtr]; containers:linkedlist(next, null). + + loop map (childrenRaw->childRaw:: xmlNodePtr):: XmlTree { + [toXmlNode(childRaw), children(childRaw)] + } +} - b = loop map (a1 -> el: num) : [num] - {2 * el;}; - - c = b : [num]; - - d = loop fold (a2->el: num, 0->acc: num): [num] - {acc + el;}; + +document = function (filename:: string):: XmlTree +{ + docRaw = xmlParseFile(filename) :: xmlDocPtr. + nodeRaw= xmlDocGetRootElement(docRaw) :: xmlNodePtr. - c[5]==d; + [toXmlNode(nodeRaw), children(nodeRaw)]:: XmlTree } +*/ + + + +/* +query = function (tree:: XmlTree):: [string, string] +{ + children = switch :: context(children) + case default + { [] } + + case tree[0]:: NeedChildren(childrenFilters); ApplyTransform(transFilters) + { + loop fold (tree[1]->child:: Tree(Leaf) | childrenFilters, null->accum:: [Tree(Leaf)]) + :: [Tree(Leaf)] + {accum + traverse(child):: cases(transFilters) } + }. + + node = + case node_tag == "style::style", class = node[attrs, "style::name"], exists(class, ParaKnownClasses) + { + [class, node[attrs, "style::display-name"]] + } + + case default + {null}. + + node + children +} +*/ + + diff --git a/scripts/intersection.li2 b/scripts/intersection.li2 deleted file mode 100644 index 6ce957a..0000000 --- a/scripts/intersection.li2 +++ /dev/null @@ -1,93 +0,0 @@ -// пример реализации процедуры определения пересечения двух множеств -// -// -// A, B - два множества - - -Iterator (Set set) : (Set set, int pos) - -next(Iterator Set i): action of Iterator{ - pos++; - - return i; -} - -written El_Type x = Iterator/Set/El_Type i : substitution{ - x = i.pos; -} - - -A overtake B: action of Iterator { - elB = current (B); //эта команда может превратиться просто в использование elA из вызывающей функции, используя аннотацию context или bag - - repeat-post elA elB) - elB = B overtake A; - else - elA = A overake B; - - if (elA == elB) - put(RESULT-SET, elA); - -return RESULT-SET -} - -// repeat - бесконечный повтор? -// repeat-pre - повтор с предусловием, repeat-post - повтор с постусловием - - - - - Работа с Map: - Пример отображения(view), пример №1: - -Map/(KEY, VALUE): type = [(KEY, VALUE)]; - -Map-T ([KEY], [VALUE]): view, pairs: Map/(KEY, VALUE) = { - keys = map pairs, pair - (key, ) = pair; - key - - values = map pairs, pair - (, value) = pair; - value - - return (keys, values) -} - -//(SELECT key, SELECT value) - возможно ли в функцию передавать названия поля, с кот. ей нужно работать.. ? - - Пример №2 (свести к поиску 6): - -find6: function = { -x: [int] = [1, 2, 3, 4, 5, 6, 7]; //эффективная инициализация! - -y = map x, el - 2 * el - -return exists(x, 12); -} - - -/** - * Построить: - * сортировка :- необходимо ordered-list(linked-list, tree-list) - * RA доступ :- желательно hash-list или желательно tree-list - * последовательный доступ :- желательно ordered-list - * - * -Necessarily and ◇ for Possibly \ No newline at end of file diff --git a/scripts/opcode.comments b/scripts/opcode.comments deleted file mode 100644 index 31c457b..0000000 --- a/scripts/opcode.comments +++ /dev/null @@ -1,30 +0,0 @@ - -/* - -ASTLispNode - - -transform( - - function(__name, __vars), function(name(__name), vars-list(__vars), body(function.body) -) -*/ - - -add(y, div(add(x, 5), 15)))) - - -opcode(add, LLVMAddInstruction) -opcode(div, LLVMDivideInstruction) - -function(name(first-function), - vars-list(var(name(x), type(i32)), var(name(y), type(i32))), - return(type(i32)), - body( - div(add(x, 5), y))) - -function (name(second-f), vars-list, return(type(i32)), body( - add(add (10, 20), first-function(11, 80)) -)) - -main(second-f) \ No newline at end of file diff --git a/scripts/opcode.li b/scripts/opcode.li deleted file mode 100644 index 5f62311..0000000 --- a/scripts/opcode.li +++ /dev/null @@ -1,14 +0,0 @@ -opcode(add, LLVMAddInstruction) -opcode(div, LLVMDivideInstruction) - -function(name(first-function), - vars-list(var(name(x), type(i32)), var(name(y), type(i32))), - return(type(i32)), - body( - div(add(x, 5), y))) - -function (name(second-f), vars-list, return(type(i32)), body( - add(add (10, 20), first-function(80, 11)) -)) - -main(second-f) \ No newline at end of file diff --git a/scripts/testspass/Containers_Implementation_LinkedList1.xreate b/scripts/testspass/Containers_Implementation_LinkedList1.xreate new file mode 100644 index 0000000..cbc893d --- /dev/null +++ b/scripts/testspass/Containers_Implementation_LinkedList1.xreate @@ -0,0 +1,47 @@ + + // EXTERN INCLUDES +interface(extern-c){ + xml2 = library:: pkgconfig("libxml-2.0"). + + include { + xml2 = ["libxml/tree.h"] + }. +} + + // CONTAINERS +interface(dfa) { + operator map:: (op(seqaccess)) -> impl(solid). + operator list_range:: ()->impl(on_the_fly). + operator list:: ()->impl(solid). + operator fold:: (op(seqaccess)). + operator index:: (op(randaccess)). + /* operator map: (op(seqaccess)) -> impl(llvm_array | on_the_fly); */ +} + +import raw("core/containers.lp"). + + + // PROGRAM +XmlNode = type alias { + tag:: string, + /* attrs:: [string],*/ + content:: string +}. + +Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]. +XmlTree = type alias Tree(XmlNode). + + +test= function():: num; entry { + filename = "project/documentation.fodt" :: string. + docRaw = xmlParseFile(filename) :: xmlDocPtr. + tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr. + childrenRaw = tree["children"]:: [xmlNodePtr]; containers:linkedlist(next, null). + size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count::int):: int { + count +1::int + }. + + size +} + + diff --git a/scripts/xml/xml-backup.xreate b/scripts/xml/xml-backup.xreate new file mode 100644 index 0000000..7fe9246 --- /dev/null +++ b/scripts/xml/xml-backup.xreate @@ -0,0 +1,65 @@ +default_filname = "project/documentation.fodt" : string; + +/* require ptrvalid */ +/* local scope doc ptr */ + +XmlNode = type { + tag: string; + attrs: [string]; + content: string}. + +Tree = type(Leaf) Tree [Leaf; [Tree(Leaf)]]; + +XmlTree = Tree(XmlNode); + + +children = function: (tree: xmlNodePtr)->XmlTree +{ + childrenRaw = tree[xmlChildrenNode]: [xmlNodePtr], linkedlist(next, null); + + map (childrenRaw->childRaw: xmlNodePtr) { + Tree[childRaw[name] children(childRaw)] + } +} + + +document = function: (filename: string)->XmlTree +{ + docRaw = xmlParseFile(docname.c_str()) : xmlDocPtr; + nodeRaw= xmlDocGetRootElement(docRaw) : xmlNodePtr; + + Tree [nodeRaw[name] children(nodeRaw)); +} + + +query = function: (tree: XmlTree) [string, string] +{ + children : context(children) = + case default + [] + + case (tree[0]: NeedChildren(childrenFilters), ApplyTransform(transFilters)) + { + loop fold (tree[1]->child: Tree(Leaf) | childrenFilters; []->accum). + {accum + traverse(child): cases(transFilters) }; + } + + node = + case (node.tag == "style:style"; class = node[attrs, "style:name"]; exists(class, ParaKnownClasses)) + { + [class, node[attrs, "style:display-name"]]; + } + + case default + [] ; + + node + children; +} + + +test = function: ()->num +{ + data = query(document(default_filename)): [string, string]; + + exists(data, "pgess1"). +} diff --git a/scripts/xml/xml-client.xreate b/scripts/xml/xml-client.xreate new file mode 100644 index 0000000..dc1b2cb --- /dev/null +++ b/scripts/xml/xml-client.xreate @@ -0,0 +1,71 @@ +/* + +Example of c++ code: + + xmlDocPtr doc; + xmlNodePtr cur; + doc = xmlParseFile(docname.c_str()); + if (doc == NULL ) { + fprintf(stderr,"Document not parsed successfully. \n"); + return; + } + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + fprintf(stderr,"empty document\n"); + xmlFreeDoc(doc); + return; + } + + cur = cur->xmlChildrenNode; + while (cur != NULL) { + printf("child: %s\n", cur->name); + + cur = cur->next; + } + +*/ + +/* + + Default strategies: + - what to do with unspecified nodes + + Node content strategy: + - send as-is + - apply transforms (all / named) + - ?? skip + + Processing order: + - dependencies + + */ + +query = function(tree: XmlTree): [XmlTree] +{ + children : context(children) = + case default + [] + + case (tree[0]: NeedChildren(childrenFilters), ApplyTransform(transFilters)) + { + loop fold (tree[1]->child: Tree(Leaf) | childrenFilters; []->accum). + {accum + traverse(child): cases(transFilters) }; + } + + node = + case (node.tag == "style:style"; class = node[attrs, "style:name"]; exists(class, ParaKnownClasses)) + { + [class, node[attrs, "style:display-name"]]; + } + + case default + [] ; + + Tree[node children] | node + children +} + + /* +traverse = function(trees: [XmlTree]) : [XmlTree] + loop fold(trees->tree: Tree; []->acc) + acc + traverse(tree) + */ \ No newline at end of file diff --git a/scripts/xml/xml-query.xreate b/scripts/xml/xml-query.xreate new file mode 100644 index 0000000..60a330e --- /dev/null +++ b/scripts/xml/xml-query.xreate @@ -0,0 +1,38 @@ +XmlNode = type { + tag: string; + attrs: [string]; + content: string}. + +Tree = type(Leaf) Tree [Leaf; [Tree(Leaf)]]. + +XmlTree = Tree(XmlNode). + +query = function(tree: XmlTree): [XmlTree] +{ + children : context(children) = + case default + [] + + case (tree[0]: NeedChildren(childrenFilters), ApplyTransform(transFilters)) + { + loop fold (tree[1]->child: Tree(Leaf) | childrenFilters; []->accum). + {accum + traverse(child): cases(transFilters) }; + } + + node = + case (node.tag == "style:style"; class = node[attrs, "style:name"]; exists(class, ParaKnownClasses)) + { + [class, node[attrs, "style:display-name"]]; + } + + case default + [] ; + + Tree[node children] | node + children +} + + /* +traverse = function(trees: [XmlTree]) : [XmlTree] + loop fold(trees->tree: Tree; []->acc) + acc + traverse(tree) + */ \ No newline at end of file diff --git a/src/main/java/org/xreate/ASTNode.java b/src/main/java/org/xreate/ASTNode.java deleted file mode 100644 index 02b1e07..0000000 --- a/src/main/java/org/xreate/ASTNode.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.xreate; - -import com.google.common.collect.ListMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - - -public class ASTNode{ - public ASTNode acceptComputableVisitor(ComputableAnalysis visitor) throws NoSuchMethodException, IllegalAccessException, Throwable{ - Method compute = visitor.getClass().getDeclaredMethod("ifComputable", this.getClass()); - - ASTNode v = (ASTNode) compute.invoke(visitor, this); - - return new ASTValue(0); - } -} - -class ASTAssignment extends ASTNode{ - public ASTVar var; - public ASTExpression value; -} - -class ASTExpression extends ASTNode{ - ListMultimap representation; - - public List getUsedVars(){ - return Lists.newArrayList(); //stub - } - - - public ASTNode eval(Map substitutions) - {return new ASTValue(0);} //stub - -} - -class ASTFunction extends ASTNode{ - String representation; - int fpcount; //formal parameters count -} - - -class ASTValue extends ASTExpression{ - public int representation; - - public ASTValue(int source){ - representation = source; - } -} - -class ASTVar extends ASTExpression{ - int id; - - public static Map substitute(List vars) - {return Maps.newHashMap();} - - public ASTVar(){ - id =0; - } -} - - - - -/* - * fargs - formal args - * - * - * - */ - -/* - * - * - * block (fargs, body-list) - * expression -: atom - * atom :- val, var - * assignment - * sequence - * - */ - diff --git a/src/main/java/org/xreate/App.java b/src/main/java/org/xreate/App.java deleted file mode 100644 index ba10572..0000000 --- a/src/main/java/org/xreate/App.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.xreate; - -public class App -{ - public static void main( String[] args ) throws NoSuchMethodException, IllegalAccessException, Throwable { - TestRunner2 runner = new TestRunner2(); - - runner.constructAndRun(); - } -} diff --git a/src/main/java/org/xreate/ComputableAnalisys.java b/src/main/java/org/xreate/ComputableAnalisys.java deleted file mode 100644 index d64a7cc..0000000 --- a/src/main/java/org/xreate/ComputableAnalisys.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.xreate; - -import java.util.List; -import java.util.Map; - -/** - * - * @author pgess - */ -class ComputableAnalysis{ - protected Map computedStore; - - public ASTNode ifComputable (ASTNode node){ - return node; - } - - /* - * null - если не переменная не вычислима - */ - public ASTNode ifComputable (ASTVar node){ - - return computedStore.get(node); - - /* - Optional value = Optional.of (); - return false; - */ - } - - /* - * null - если выражение не вычислимо - */ - /* - public ASTNode ifComputable (ASTExpression node){ - List vars = node.getUsedVars(); - - Map subs = ASTVar.substitute(vars); - - if (computedStore.keySet().containsAll(vars)){ - - //computedStore. - ASTNode result = node.eval(subs); - return result; - } - - - return null; - } - - */ - - public ASTNode ifComputable (ASTAssignment node) throws NoSuchMethodException, IllegalAccessException, Throwable{ - - ASTNode value = node.value.acceptComputableVisitor(this); - - if (value != null){ - computedStore.put(node.var, value); - } - - return value; - } -} \ No newline at end of file diff --git a/src/main/java/org/xreate/SemanticAnalysis.java b/src/main/java/org/xreate/SemanticAnalysis.java deleted file mode 100644 index a411db6..0000000 --- a/src/main/java/org/xreate/SemanticAnalysis.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.xreate; - -import java.util.Map; - -/** - * - * @author pgess - */ -public class SemanticAnalysis { - public Map opcodes; -} diff --git a/src/main/java/org/xreate/TestRunner2.java b/src/main/java/org/xreate/TestRunner2.java deleted file mode 100644 index 5c519c4..0000000 --- a/src/main/java/org/xreate/TestRunner2.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.xreate; - -import com.google.common.collect.Maps; -import java.math.BigInteger; -import org.jllvm.*; -import org.jllvm.bindings.*; -import org.junit.Test; -/** - * - * @author pgess - */ -public class TestRunner2 { - - protected LLVMModule module; - - public void setModule(LLVMModule module){ - this.module = module; - } - - public void constructAndRun() throws Exception{ - boolean isNative = LLVMTargetData.initializeNativeTarget(); - module = new LLVMModule("xreate_first_test"); - - LLVMValue func = constructBody(); - runBody(func); - } - - public LLVMValue constructBody() throws Exception{ - LLVMConstantInteger a = LLVMConstantInteger.constantInteger(LLVMIntegerType.i32, 10, true); - LLVMConstantInteger b = LLVMConstantInteger.constantInteger(LLVMIntegerType.i32, 20, true); - LLVMConstantInteger c = LLVMConstantInteger.constantInteger(LLVMIntegerType.i32, 3, true); - LLVMInstructionBuilder builder = new LLVMInstructionBuilder(); - - LLVMInstruction i = new LLVMAddInstruction(builder, a, b, false, "a+b"); - i = new LLVMMultiplyInstruction(builder, c, i, false, "c * (a + b)"); - - //LLVMModule module; // module = - LLVMFunctionType func_test1_type; - - - - LLVMType[] types = new LLVMType[0]; - //types[0] = new LLVMVoidType(); - - func_test1_type = new LLVMFunctionType(LLVMIntegerType.i32, types, false); - - LLVMFunction test1 = new LLVMFunction(module, "test1", func_test1_type); - LLVMBasicBlock entry = test1.appendBasicBlock("entry"); - builder.positionBuilderAtEnd(entry); - - new LLVMReturnInstruction(builder, i); - - SWIGTYPE_p_p_char outerrs = ExecutionEngine.new_StringArray(1); - int x = Analysis.LLVMVerifyFunction(test1.getInstance(), LLVMVerifierFailureAction.LLVMReturnStatusAction); - x = Analysis.LLVMVerifyModule(module.getInstance(), LLVMVerifierFailureAction.LLVMReturnStatusAction, outerrs); - - ExecutionEngine.delete_StringArray(outerrs); outerrs = null; - - return test1; - } - - public void runBody(LLVMValue test1 ){ - - - SWIGTYPE_p_p_LLVMOpaqueExecutionEngine engines = ExecutionEngine.new_LLVMExecutionEngineRefArray(1); - SWIGTYPE_p_p_char outerrs = ExecutionEngine.new_StringArray(1); - int success = ExecutionEngine.LLVMCreateJITCompilerForModule(engines,module.getInstance(), 0, outerrs); - String outerr = ExecutionEngine.StringArray_getitem(outerrs,0); - ExecutionEngine.delete_StringArray(outerrs); outerrs = null; - SWIGTYPE_p_LLVMOpaqueExecutionEngine instance_ = ExecutionEngine.LLVMExecutionEngineRefArray_getitem(engines,0); - ExecutionEngine.delete_LLVMExecutionEngineRefArray(engines); engines = null; - - /* - LLVMJitCompiler engine = new LLVMJitCompiler(module); - - LLVMGenericValue res = engine.runFunction(test1, args); - - // - BigInteger result = ExecutionEngine.LLVMGenericValueToInt(res.getInstance(), 0); - */ - - LLVMGenericValue[] args = new LLVMGenericValue[0]; - - - SWIGTYPE_p_p_LLVMOpaqueGenericValue arg_array = ExecutionEngine.new_LLVMGenericValueRefArray(args.length); - for(int ii=0;ii parameters = Lists.newArrayList(); - - protected Map index; - - public ASTLispNode(String c){ - caption = c; - } - - public ASTLispNode add(ASTLispNode node){ - parameters.add(node); - return node; - } - - public ASTLispNode get(String node){ - if (null == index){ - buildIndex(); - } - - return index.get(node); - } - - protected void buildIndex(){ - index = Maps.newHashMap(); - - for (ASTLispNode param : parameters){ - index.put(param.caption, param); - } - } -} -class ASTLispConstantNode extends ASTLispNode{ - public int value; - - public ASTLispConstantNode(String c) { - super(c); - - value = Integer.parseInt(c); - } -} - - -class NodeFunctionVarsList { - ASTLispNode node; - - NodeFunctionVarsList(ASTLispNode node){ - this.node = node; - } - - String[] getVarNames(){ - int size = node.parameters.size(); - - String[] result = new String[size]; - - for(int i=0; i htable; - static Map ttable; - - public Map opcodes = Maps.newLinkedHashMap(); - public Map functions = Maps.newLinkedHashMap(); - - - protected LLVMInstructionBuilder builder = new LLVMInstructionBuilder(); - protected LLVMModule module = new LLVMModule("script"); - - //"/private/prg/code/xreate/scripts/opcode.li" - public void run(String filename) throws IOException, RecognitionException, Exception{ - ANTLRStringStream in = new ANTLRFileStream(filename); - - Lexer l = new LispLexer(in); - CommonTokenStream tokens = new CommonTokenStream(l); - - LispParser p = new LispParser(tokens); - - while (true){ - ASTLispNode node = p.statement(null); - - handle(node); - } - - } - - public void opcodeDef(ASTLispNode node){ - ArrayList params = node.parameters; - - opcodes.put(params.get(0).caption, params.get(1).caption); - } - - public void functionDef(ASTLispNode node) throws Exception{ - ArrayList nodes_vars = node.get("vars-list").parameters; - - int nsize = nodes_vars.size(); - LLVMType[] arg_types = new LLVMType[nsize]; - - for (int i=0; i() - .put("opcode", "opcodeDef") - .put("function", "functionDef") - .put ("calculate", "calculate") - .put("main", "main") - .build(); - - /* - * Types Table - хранит информацию о соответствии типов - */ - ttable = new ImmutableMap.Builder() - .put ("i32", LLVMIntegerType.i32) - .put ("i16", LLVMIntegerType.i16) - .put ("i8", LLVMIntegerType.i8) - .build(); - - - } - - class Evaluator{ - Map arguments; - - public Evaluator(String[] names, LLVMValue[] values) { - - int size = names.length; - arguments = Maps.newHashMapWithExpectedSize(size); - - for(int i=0; i= '\t' && LA1_0 <= '\n')||(LA1_0 >= '\f' && LA1_0 <= '\r')||LA1_0==' ') ) { - alt1=1; - } - - - switch (alt1) { - case 1 : - // /private/prg/code/xreate/antlr/lisp.g: - { - if ( (input.LA(1) >= '\t' && input.LA(1) <= '\n')||(input.LA(1) >= '\f' && input.LA(1) <= '\r')||input.LA(1)==' ' ) { - input.consume(); - } - else { - MismatchedSetException mse = new MismatchedSetException(null,input); - recover(mse); - throw mse; - } - - - } - break; - - default : - if ( cnt1 >= 1 ) break loop1; - EarlyExitException eee = - new EarlyExitException(1, input); - throw eee; - } - cnt1++; - } while (true); - - - _channel = HIDDEN; - - } - - state.type = _type; - state.channel = _channel; - } - finally { - // do for sure before leaving - } - } - // $ANTLR end "WHITESPACE" - - // $ANTLR start "WORD" - public final void mWORD() throws RecognitionException { - try { - int _type = WORD; - int _channel = DEFAULT_TOKEN_CHANNEL; - // /private/prg/code/xreate/antlr/lisp.g:5:6: ( ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' )+ ) - // /private/prg/code/xreate/antlr/lisp.g:5:8: ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' )+ - { - // /private/prg/code/xreate/antlr/lisp.g:5:8: ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' )+ - int cnt2=0; - loop2: - do { - int alt2=2; - int LA2_0 = input.LA(1); - - if ( ((LA2_0 >= '0' && LA2_0 <= '9')||(LA2_0 >= 'A' && LA2_0 <= 'Z')||LA2_0=='_'||input.LA(1)=='-'||(LA2_0 >= 'a' && LA2_0 <= 'z')) ) { - alt2=1; - } - - - switch (alt2) { - case 1 : - // /private/prg/code/xreate/antlr/lisp.g: - { - if ( (input.LA(1) >= '0' && input.LA(1) <= '9')||(input.LA(1) >= 'A' && input.LA(1) <= 'Z')||input.LA(1)=='_' ||input.LA(1)=='-' ||(input.LA(1) >= 'a' && input.LA(1) <= 'z') ) { - input.consume(); - } - else { - MismatchedSetException mse = new MismatchedSetException(null,input); - recover(mse); - throw mse; - } - - - } - break; - - default : - if ( cnt2 >= 1 ) break loop2; - EarlyExitException eee = - new EarlyExitException(2, input); - throw eee; - } - cnt2++; - } while (true); - - - } - - state.type = _type; - state.channel = _channel; - } - finally { - // do for sure before leaving - } - } - // $ANTLR end "WORD" - - public void mTokens() throws RecognitionException { - // /private/prg/code/xreate/antlr/lisp.g:1:8: ( T__6 | T__7 | T__8 | WHITESPACE | WORD ) - int alt3=5; - switch ( input.LA(1) ) { - case '(': - { - alt3=1; - } - break; - case ')': - { - alt3=2; - } - break; - case ',': - { - alt3=3; - } - break; - case '\t': - case '\n': - case '\f': - case '\r': - case ' ': - { - alt3=4; - } - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - case 'G': - case 'H': - case 'I': - case 'J': - case 'K': - case 'L': - case 'M': - case 'N': - case 'O': - case 'P': - case 'Q': - case 'R': - case 'S': - case 'T': - case 'U': - case 'V': - case 'W': - case 'X': - case 'Y': - case 'Z': - case '_': - case '-': - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - case 'h': - case 'i': - case 'j': - case 'k': - case 'l': - case 'm': - case 'n': - case 'o': - case 'p': - case 'q': - case 'r': - case 's': - case 't': - case 'u': - case 'v': - case 'w': - case 'x': - case 'y': - case 'z': - { - alt3=5; - } - break; - default: - NoViableAltException nvae = - new NoViableAltException("", 3, 0, input); - - throw nvae; - - } - - switch (alt3) { - case 1 : - // /private/prg/code/xreate/antlr/lisp.g:1:10: T__6 - { - mT__6(); - - - } - break; - case 2 : - // /private/prg/code/xreate/antlr/lisp.g:1:15: T__7 - { - mT__7(); - - - } - break; - case 3 : - // /private/prg/code/xreate/antlr/lisp.g:1:20: T__8 - { - mT__8(); - - - } - break; - case 4 : - // /private/prg/code/xreate/antlr/lisp.g:1:25: WHITESPACE - { - mWHITESPACE(); - - - } - break; - case 5 : - // /private/prg/code/xreate/antlr/lisp.g:1:36: WORD - { - mWORD(); - - - } - break; - - } - - } - - - - -} \ No newline at end of file diff --git a/src/main/java/org/xreate/grammatic/lisp/LispParser.java b/src/main/java/org/xreate/grammatic/lisp/LispParser.java deleted file mode 100644 index 19d8dea..0000000 --- a/src/main/java/org/xreate/grammatic/lisp/LispParser.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.xreate.grammatic.lisp; - -// $ANTLR 3.4 /private/prg/code/xreate/antlr/lisp.g 2012-04-07 17:57:03 - -import org.antlr.runtime.*; -import java.util.Stack; -import java.util.List; -import java.util.ArrayList; - -@SuppressWarnings({"all", "warnings", "unchecked"}) -public class LispParser extends Parser { - public static final String[] tokenNames = new String[] { - "", "", "", "", "WHITESPACE", "WORD", "'('", "')'", "','" - }; - - public static final int EOF=-1; - public static final int T__6=6; - public static final int T__7=7; - public static final int T__8=8; - public static final int WHITESPACE=4; - public static final int WORD=5; - - // delegates - public Parser[] getDelegates() { - return new Parser[] {}; - } - - // delegators - - - public LispParser(TokenStream input) { - this(input, new RecognizerSharedState()); - } - public LispParser(TokenStream input, RecognizerSharedState state) { - super(input, state); - } - - public String[] getTokenNames() { return LispParser.tokenNames; } - public String getGrammarFileName() { return "/private/prg/code/xreate/antlr/lisp.g"; } - - - - // $ANTLR start "statement" - // /private/prg/code/xreate/antlr/lisp.g:7:1: statement : WORD ( '(' statement ( ',' statement )* ')' )? ; - public final ASTLispNode statement(ASTLispNode node) throws RecognitionException { - try { - // /private/prg/code/xreate/antlr/lisp.g:8:2: ( WORD ( '(' statement ( ',' statement )* ')' )? ) - // /private/prg/code/xreate/antlr/lisp.g:8:4: WORD ( '(' statement ( ',' statement )* ')' )? - { - CommonToken token = (CommonToken) match(input,WORD,FOLLOW_WORD_in_statement71); - - String text = token.getText(); - ASTLispNode nodeChild = ('0' <= text.charAt(0) && '9'>= text.charAt(0))? new ASTLispConstantNode(text) : new ASTLispNode(text); - if (node != null){ - node.add(nodeChild); - } - node = nodeChild; - - // /private/prg/code/xreate/antlr/lisp.g:8:9: ( '(' statement ( ',' statement )* ')' )? - int alt2=2; - int LA2_0 = input.LA(1); - - if ( (LA2_0==6) ) { - alt2=1; - } - switch (alt2) { - case 1 : - // /private/prg/code/xreate/antlr/lisp.g:8:10: '(' statement ( ',' statement )* ')' - { - match(input,6,FOLLOW_6_in_statement74); - - pushFollow(FOLLOW_statement_in_statement76); - statement(node); - - state._fsp--; - - - // /private/prg/code/xreate/antlr/lisp.g:8:24: ( ',' statement )* - loop1: - do { - int alt1=2; - int LA1_0 = input.LA(1); - - if ( (LA1_0==8) ) { - alt1=1; - } - - - switch (alt1) { - case 1 : - // /private/prg/code/xreate/antlr/lisp.g:8:25: ',' statement - { - match(input,8,FOLLOW_8_in_statement79); - - pushFollow(FOLLOW_statement_in_statement81); - statement(node); - - state._fsp--; - - - } - break; - - default : - break loop1; - } - } while (true); - - - match(input,7,FOLLOW_7_in_statement85); - - } - break; - - } - - - } - - } - catch (RecognitionException re) { - reportError(re); - recover(input,re); - } - - finally { - // do for sure before leaving - } - return node; - } - // $ANTLR end "statement" - - // Delegated rules - - - - - public static final BitSet FOLLOW_WORD_in_statement71 = new BitSet(new long[]{0x0000000000000042L}); - public static final BitSet FOLLOW_6_in_statement74 = new BitSet(new long[]{0x0000000000000020L}); - public static final BitSet FOLLOW_statement_in_statement76 = new BitSet(new long[]{0x0000000000000180L}); - public static final BitSet FOLLOW_8_in_statement79 = new BitSet(new long[]{0x0000000000000020L}); - public static final BitSet FOLLOW_statement_in_statement81 = new BitSet(new long[]{0x0000000000000180L}); - public static final BitSet FOLLOW_7_in_statement85 = new BitSet(new long[]{0x0000000000000002L}); - -} \ No newline at end of file diff --git a/src/test/java/org/xreate/ASTTest1.java b/src/test/java/org/xreate/ASTTest1.java deleted file mode 100644 index c30c808..0000000 --- a/src/test/java/org/xreate/ASTTest1.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.xreate; - -import com.google.common.collect.ListMultimap; -import com.google.common.collect.Maps; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class ASTTest1 - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public ASTTest1( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( ASTTest1.class ); - } - - /** - * Rigourous Test :-) - */ - public void testAST1() throws NoSuchMethodException, IllegalAccessException, Throwable - { - ASTVar x = new ASTVar(); - ASTValue y = new ASTValue(10); - ASTAssignment as = new ASTAssignment(); - - as.var = x; - as.value = y; - ComputableAnalysis analysis = new ComputableAnalysis(); - ASTNode result = as.acceptComputableVisitor(analysis); - - assertTrue( true ); - } -} - - - diff --git a/src/test/java/org/xreate/LispTest.java b/src/test/java/org/xreate/LispTest.java deleted file mode 100644 index e9f7bc1..0000000 --- a/src/test/java/org/xreate/LispTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.xreate; - -import java.io.IOException; -import junit.framework.TestCase; -import org.antlr.runtime.*; -import org.junit.Ignore; -import org.xreate.grammatic.lisp.ASTLispNode; -import org.xreate.grammatic.lisp.LispLexer; -import org.xreate.grammatic.lisp.LispParser; - -import static org.junit.Assert.*; -import org.junit.Test; -import org.xreate.grammatic.lisp.LispInterpreter; -/** - * - * @author pgess - */ -public class LispTest { - static int z; - - @Ignore - @Test - public void test1() throws RecognitionException{ - assertTrue(true); - - ANTLRStringStream in = new ANTLRStringStream("aa(bb, cc(dd, ee))"); - - Lexer l = new LispLexer(in); - CommonTokenStream tokens = new CommonTokenStream(l); - - LispParser p = new LispParser(tokens); - - ASTLispNode node = p.statement(null); - - int x = 0; - } - - @Ignore - @Test - public void test2() throws IOException, RecognitionException{ - ANTLRStringStream in = new ANTLRFileStream("/private/prg/code/xreate/scripts/opcode.li"); - - Lexer l = new LispLexer(in); - CommonTokenStream tokens = new CommonTokenStream(l); - - LispParser p = new LispParser(tokens); - - ASTLispNode node = p.statement(null); - - int x = 0; - } - - @Test - public void test3() throws Exception{ - LispInterpreter lisp = new LispInterpreter(); - - lisp.run("/private/prg/code/xreate/scripts/opcode.li"); - - //assertEquals(answer, 100); - } - - static { - System.loadLibrary("jllvm"); - } -}