diff --git a/CMakeLists.txt b/CMakeLists.txt index 86a9430..eb76ade 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.7) -project(dpro) +project(dbuild) set(THIRD_PARTY_INCLUDE_DIRS third_party) set(SRC_DIRS src) diff --git a/default.nix b/default.nix index 84b3888..dea883a 100644 --- a/default.nix +++ b/default.nix @@ -1,6 +1,6 @@ { pkgs ? import { } }: pkgs.stdenv.mkDerivation rec { - pname = "dpro"; + pname = "dbuild"; version = "0.1.0"; src = ./.; @@ -20,6 +20,6 @@ pkgs.stdenv.mkDerivation rec { installPhase = '' mkdir -p $out/bin - mv dpro $out/bin + mv dbuild $out/bin ''; } diff --git a/src/context.cpp b/src/context.cpp index 97b8b91..91d20a5 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -4,4 +4,180 @@ void Context::error(std::string_view msg) { std::cout << "Error! " << msg << std::endl; +} + +using std::any_cast; + +std::any Context::readIdentifier(std::any val) { + assert(val.type() == typeid(Identifier)); + return currentScope->getVar(*this, any_cast(val).identifier); +} + +/** + * Returns the value of the input (reads the value if it is a refers to a variable) + */ +std::any Context::getValue(std::any input) { + if (input.type() == typeid(Identifier)) + return readIdentifier(input); + else + return input; +} + +std::any Context::eval(peg::Ast& ast) { + const auto &nodes = ast.nodes; + if (ast.name == "Root") { + for (int i=0; i(eval(*nodes[0])); + auto value = eval(*nodes[1]); + currentScope->writeVar(*this, identifier.identifier, value); + return Nil(); + } else if (ast.name == "IDENTIFIER" || ast.name == "BUILTINIDENTIFIER") { + return Identifier(std::string(ast.token_to_string())); + } else if (ast.name == "INTEGER") { + // TODO parse hex, oct, and binary + return ast.token_to_number(); + } else if (ast.name == "BUILTINCALL" ) { + auto identifier = any_cast(eval(*nodes[0])); + auto args = Args::toArgs(*this, eval(*nodes[1])); + builtins.at(identifier.identifier).execute(*this, args); + // TODO: handle returns + return Nil(); + } else if (ast.name == "STRINGLITERALSINGLE") + { + return ast.token_to_string(); + } else if (ast.name == "ExprList") { + std::vector exprs; + for (int i=0; i(value) + any_cast(v2); + } else { + value = any_cast(value) - any_cast(v2); + } + } + return value; + } else if (ast.name == "MultiplyExpr") { + auto value = getValue(eval(*nodes[0])); + for (int i=1; i(value) * any_cast(v2); + } else { + value = any_cast(value) / any_cast(v2); + } + } + return value; + } else if (ast.name == "AssignExpr") { + std::string name = any_cast(eval(*nodes[0])).identifier; + // TODO arrays, dot operator, etc. + auto v1 = currentScope->getVar(*this, name); + int op = (*nodes[1]).choice; + auto v2 = getValue(eval(*nodes[2])); + std::any result; + // TODO: floats + if (op == 0) { + result = any_cast(v1) * any_cast(v2); + } else if (op == 1) { + result = any_cast(v1) % any_cast(v2); + } else if (op == 2) { + result = any_cast(v1) + any_cast(v2); + } else if (op == 3) { + result = any_cast(v1) - any_cast(v2); + } else if (op == 4) { + result = any_cast(v1) & any_cast(v2); + } else if (op == 5) { + result = any_cast(v1) ^ any_cast(v2); + } else if (op == 6) { + result = any_cast(v1) | any_cast(v2); + } else if (op == 7) { + result = v2; + } + currentScope->writeVar(*this, name, result); + return result; + } else if (ast.name == "PrimaryTypeExpr") { + int op = ast.choice; + if (op == 8) { + return false; + } else if (op == 9) { + return Nil(); + } else if (op == 10) { + return true; + } + } else if (ast.name == "CompareExpr") { + auto v1 = getValue(eval(*nodes[0])); + int op = (*nodes[1]).choice; + auto v2 = getValue(eval(*nodes[2])); + // TODO: floats, bool, etc. + if (op == 0) { + return (bool)(any_cast(v1) == any_cast(v2)); + } else if (op == 1) { + return (bool)(any_cast(v1) != any_cast(v2)); + } else if (op == 2) { + return (bool)(any_cast(v1) < any_cast(v2)); + } else if (op == 3) { + return (bool)(any_cast(v1) > any_cast(v2)); + } else if (op == 4) { + return (bool)(any_cast(v1) <= any_cast(v2)); + } else if (op == 5) { + return (bool)(any_cast(v1) >= any_cast(v2)); + } + } else if (ast.name == "IfStatement") { + auto val = getValue(eval(*nodes[0])); + if (any_cast(val)) { + return eval(*nodes[1]); + } else { + return eval(*nodes[2]); + } + } else if (ast.name == "Block") { + // TODO create new scope + std::any result = Nil(); + for (int i=0; i(getValue(eval(*nodes[0])))) { + result = eval(*nodes[1]); + } + return result; + } else if (ast.name == "Fn") { + auto identifiers = any_cast>(eval(*nodes[0])); + return Func(nodes[1], identifiers); + } else if (ast.name == "ParamDeclList") { + std::vector identifiers; + for (int i=0; i(eval(*nodes[i]))); + } + return identifiers; + } else if (ast.name == "SuffixExpr") { + // TODO handle other PrimaryTypeExpr types + auto val = getValue(eval(*nodes[0])); + auto func = any_cast(val); + for (int i=1; i currentScope; public: void error(std::string_view msg); + std::any eval(peg::Ast& ast); +protected: + std::any readIdentifier(std::any val); + std::any getValue(std::any input); }; \ No newline at end of file diff --git a/src/grammar.peg b/src/grammar.peg index 317d427..c5a92b7 100644 --- a/src/grammar.peg +++ b/src/grammar.peg @@ -13,23 +13,15 @@ Statement / LabeledStatement / AssignExpr SEMICOLON -IfStatement - <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )? - / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) +IfStatement <- IfPrefix Block ( KEYWORD_else Payload? Block )? LabeledStatement <- BlockLabel? (Block / LoopStatement) LoopStatement <- ForStatement / WhileStatement -ForStatement - <- ForPrefix BlockExpr ( KEYWORD_else Statement )? - / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement ) +ForStatement <- ForPrefix Block -WhileStatement - <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )? - / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) - -BlockExpr <- BlockLabel? Block +WhileStatement <- WhilePrefix Block # *** Expression Level *** AssignExpr <- Expr (AssignOp Expr)? @@ -71,8 +63,7 @@ ForExpr <- ForPrefix Expr (KEYWORD_else Expr)? WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? -SuffixExpr - <- PrimaryTypeExpr (SuffixOp / FnCallArguments)* +SuffixExpr <- PrimaryTypeExpr (SuffixOp / FnCallArguments)* PrimaryTypeExpr <- BUILTINCALL @@ -120,7 +111,6 @@ AssignOp / AMPERSANDEQUAL / CARETEQUAL / PIPEEQUAL - / ASTERISKPERCENTEQUAL / EQUAL CompareOp @@ -148,8 +138,6 @@ MultiplyOp <- ASTERISK / SLASH / PERCENT - / ASTERISK2 - / ASTERISKPERCENT PrefixOp <- EXCLAMATIONMARK @@ -163,9 +151,9 @@ SuffixOp FnCallArguments <- LPAREN ExprList RPAREN # Lists -ExprList <- (Expr COMMA)* Expr? +ExprList <- (Expr COMMA)* Expr? { no_ast_opt } -ParamDeclList <- (IDENTIFIER COMMA)* IDENTIFIER? +ParamDeclList <- (IDENTIFIER COMMA)* IDENTIFIER? { no_ast_opt } # *** Tokens *** INTEGER @@ -253,10 +241,7 @@ STRINGLITERALSINGLE <- "\"" < string_char* > "\"" skip ~AMPERSAND <- '&' ![=] skip ~AMPERSANDEQUAL <- '&=' skip ~ASTERISK <- '*' ![*%=] skip -~ASTERISK2 <- '**' skip ~ASTERISKEQUAL <- '*=' skip -~ASTERISKPERCENT <- '*%' ![=] skip -~ASTERISKPERCENTEQUAL <- '*%=' skip ~CARET <- '^' ![=] skip ~CARETEQUAL <- '^=' skip ~COLON <- ':' skip diff --git a/src/main.cpp b/src/main.cpp index a4d64f0..fe1f1c8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,139 +7,6 @@ #include "context.h" #include "util.h" -using peg::SemanticValues; -using std::any_cast; - -int main_old(void) { - // (2) Make a parser - peg::parser parser(R"( - # Grammar for Calculator... - Additive <- Multitive '+' Additive / Multitive - Multitive <- Primary '*' Multitive / Primary - Primary <- '(' Additive ')' / Number - Number <- < [0-9]+ > - %whitespace <- [ \t]* - )"); - - assert(static_cast(parser) == true); - - // (3) Setup actions - parser["Additive"] = [](const SemanticValues &vs) { - switch (vs.choice()) { - case 0: // "Multitive '+' Additive" - return any_cast(vs[0]) + any_cast(vs[1]); - default: // "Multitive" - return any_cast(vs[0]); - } - }; - - parser["Multitive"] = [](const SemanticValues &vs) { - switch (vs.choice()) { - case 0: // "Primary '*' Multitive" - return any_cast(vs[0]) * any_cast(vs[1]); - default: // "Primary" - return any_cast(vs[0]); - } - }; - - parser["Number"] = [](const SemanticValues &vs) { - return vs.token_to_number(); - }; - - // (4) Parse - parser.enable_packrat_parsing(); // Enable packrat parsing. - - int val; - parser.parse(" (1 + 2) * 3 ", val); - - assert(val == 9); - - return 0; -} - -std::any readIdentifier(Context &cxt, std::any val) { - assert(val.type() == typeid(Identifier)); - return cxt.currentScope->getVar(cxt, any_cast(val).identifier); -} - -/** - * Returns the value of the input (reads the value if it is a refers to a variable) - */ -std::any getValue(Context& cxt, std::any input) { - if (input.type() == typeid(Identifier)) - return readIdentifier(cxt, input); - else - return input; -} - -std::any eval(Context &cxt, peg::Ast& ast) { - const auto &nodes = ast.nodes; - if (ast.name == "Root") { - for (int i=0; i(eval(cxt, *nodes[0])); - auto value = eval(cxt, *nodes[1]); - cxt.currentScope->writeVar(cxt, identifier.identifier, value); - return Nil(); - } else if (ast.name == "IDENTIFIER" || ast.name == "BUILTINIDENTIFIER") { - return Identifier(std::string(ast.token_to_string())); - } else if (ast.name == "INTEGER") { - // TODO parse hex, oct, and binary - return ast.token_to_number(); - } else if (ast.name == "BUILTINCALL" ) { - auto identifier = any_cast(eval(cxt, *nodes[0])); - auto args = Args::toArgs(cxt, eval(cxt, *nodes[1])); - cxt.builtins.at(identifier.identifier).execute(cxt, args); - // TODO: handle returns - return Nil(); - } else if (ast.name == "STRINGLITERALSINGLE") - { - return ast.token_to_string(); - } else if (ast.name == "ExprList") { - std::vector exprs; - for (int i=0; i(value) + any_cast(v2); - } else { - value = any_cast(value) - any_cast(v2); - } - } - return value; - } else if (ast.name == "MultiplyExpr") { - auto value = getValue(cxt, eval(cxt, *nodes[0])); - for (int i=1; i(value) * any_cast(v2); - } else { - value = any_cast(value) / any_cast(v2); - } - } - return value; - } - - std::cout << "AST Name: " << ast.name << std::endl; - for (int i=0; i 0) { + a -= 1; + @print(a); + } + var hello = fn(abc) { + @print(abc); + }; + hello("world"); )"; parser.enable_ast(); @@ -166,7 +53,7 @@ int main(void) { cxt.builtins.emplace("print", Func(BuiltinFunctions::print)); cxt.currentScope = scope; - eval(cxt, *ast); + cxt.eval(*ast); return 0; } diff --git a/src/util.cpp b/src/util.cpp index 7b11b02..e26b036 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -6,11 +6,7 @@ Args Args::toArgs(Context& cxt, std::any input) { Args args; - if (input.type() == typeid(Identifier)) { - auto id = std::any_cast(input); - auto value = cxt.currentScope->getVar(cxt, id.identifier); - args.args.push_back(value); - } else if (input.type() == typeid(std::vector)) { + if (input.type() == typeid(std::vector)) { args.args = std::any_cast>(input); } else { cxt.error("Unimplemented toArgs"); @@ -18,16 +14,40 @@ Args Args::toArgs(Context& cxt, std::any input) { return args; } -void BuiltinFunctions::print(Context& cxt, Args& args) { +std::any Func::execute(Context& cxt, Args& args) { + if (ast == nullptr) { + return nativeFunction(cxt, args); + } else { + // TODO create scope + std::any result; + for (int i=0; iwriteVar(cxt, argNames[i].identifier, args.args[i]); + } + result = cxt.eval(*ast); + // TODO tear down scope + return result; + } +} + +std::any BuiltinFunctions::print(Context& cxt, Args& args) { for (int i=0; i(var) << '\t'; } else if (var.type() == typeid(std::string)) { std::cout << std::any_cast(var) << '\t'; + } else if (var.type() == typeid(bool)) { + bool v = std::any_cast(var); + if (v) + std::cout << "true" << '\t'; + else + std::cout << "false" << '\t'; + } else if (var.type() == typeid(Nil)) { + std::cout << "nil" << '\t'; } else { cxt.error("Attempt to print unsupported type"); } } std::cout << std::endl; + return Nil(); } \ No newline at end of file diff --git a/src/util.h b/src/util.h index 9f6d364..2caf4e4 100644 --- a/src/util.h +++ b/src/util.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -33,20 +35,29 @@ public: class Func { public: std::shared_ptr capturedScope; - // ast ptr - std::function nativeFunction; + + std::shared_ptr ast = nullptr; + std::vector argNames; + + std::function nativeFunction; public: - Func(std::function nativeFunction) + /** + * Create a native function + */ + Func(std::function nativeFunction) : capturedScope(nullptr), nativeFunction(nativeFunction) {} - void execute(Context& cxt, Args& args) { - // TODO implement AST executer - nativeFunction(cxt, args); - } + /** + * Create an interpreted function + */ + Func(std::shared_ptr ast, std::vector argNames) + : ast(ast), argNames(argNames) {} + + std::any execute(Context& cxt, Args& args); }; class BuiltinFunctions { public: - static void print(Context& cxt, Args& args); + static std::any print(Context& cxt, Args& args); }; \ No newline at end of file