functions and stuff

This commit is contained in:
zuckerberg 2021-07-10 16:40:53 -06:00
parent 4600c5f85a
commit f2b4a53176
8 changed files with 255 additions and 172 deletions

View File

@ -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)

View File

@ -1,6 +1,6 @@
{ pkgs ? import <nixpkgs> { } }:
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
'';
}

View File

@ -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<Identifier>(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<ast.nodes.size(); i++) {
eval(*nodes[i]);
}
return Nil();
} else if (ast.name == "VarDecl") {
auto identifier = any_cast<Identifier>(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<long>();
} else if (ast.name == "BUILTINCALL" ) {
auto identifier = any_cast<Identifier>(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<std::any> exprs;
for (int i=0; i<ast.nodes.size(); i++) {
exprs.push_back(getValue(eval(*nodes[i])));
}
return exprs;
} else if (ast.name == "AdditionExpr") {
auto value = getValue(eval(*nodes[0]));
for (int i=1; i<nodes.size(); i+=2) {
int op = (*nodes[i]).choice;
auto v2 = getValue(eval(*nodes[i+1]));
// TODO: floats
if (op == 0) {
value = any_cast<long>(value) + any_cast<long>(v2);
} else {
value = any_cast<long>(value) - any_cast<long>(v2);
}
}
return value;
} else if (ast.name == "MultiplyExpr") {
auto value = getValue(eval(*nodes[0]));
for (int i=1; i<nodes.size(); i+=2) {
int op = (*nodes[i]).choice;
auto v2 = getValue(eval(*nodes[i+1]));
// TODO: floats
if (op == 0) {
value = any_cast<long>(value) * any_cast<long>(v2);
} else {
value = any_cast<long>(value) / any_cast<long>(v2);
}
}
return value;
} else if (ast.name == "AssignExpr") {
std::string name = any_cast<Identifier>(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<long>(v1) * any_cast<long>(v2);
} else if (op == 1) {
result = any_cast<long>(v1) % any_cast<long>(v2);
} else if (op == 2) {
result = any_cast<long>(v1) + any_cast<long>(v2);
} else if (op == 3) {
result = any_cast<long>(v1) - any_cast<long>(v2);
} else if (op == 4) {
result = any_cast<long>(v1) & any_cast<long>(v2);
} else if (op == 5) {
result = any_cast<long>(v1) ^ any_cast<long>(v2);
} else if (op == 6) {
result = any_cast<long>(v1) | any_cast<long>(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<long>(v1) == any_cast<long>(v2));
} else if (op == 1) {
return (bool)(any_cast<long>(v1) != any_cast<long>(v2));
} else if (op == 2) {
return (bool)(any_cast<long>(v1) < any_cast<long>(v2));
} else if (op == 3) {
return (bool)(any_cast<long>(v1) > any_cast<long>(v2));
} else if (op == 4) {
return (bool)(any_cast<long>(v1) <= any_cast<long>(v2));
} else if (op == 5) {
return (bool)(any_cast<long>(v1) >= any_cast<long>(v2));
}
} else if (ast.name == "IfStatement") {
auto val = getValue(eval(*nodes[0]));
if (any_cast<bool>(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<ast.nodes.size(); i++) {
result = eval(*nodes[i]);
}
return result;
} else if (ast.name == "WhileStatement") {
std::any result = Nil();
while (any_cast<bool>(getValue(eval(*nodes[0])))) {
result = eval(*nodes[1]);
}
return result;
} else if (ast.name == "Fn") {
auto identifiers = any_cast<std::vector<Identifier>>(eval(*nodes[0]));
return Func(nodes[1], identifiers);
} else if (ast.name == "ParamDeclList") {
std::vector<Identifier> identifiers;
for (int i=0; i<nodes.size(); i++) {
identifiers.push_back(any_cast<Identifier>(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<Func>(val);
for (int i=1; i<nodes.size(); i++) {
auto args = Args::toArgs(*this, eval(*nodes[i]));
return func.execute(*this, args);
}
}
std::cout << "AST Name: " << ast.name << std::endl;
for (int i=0; i<ast.nodes.size(); i++) {
std::cout << "AST child: " << ast.name << " : ";
eval(*nodes[i]);
}
return Nil();
}

View File

@ -13,4 +13,8 @@ public:
std::shared_ptr<Scope> 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);
};

View File

@ -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

View File

@ -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<bool>(parser) == true);
// (3) Setup actions
parser["Additive"] = [](const SemanticValues &vs) {
switch (vs.choice()) {
case 0: // "Multitive '+' Additive"
return any_cast<int>(vs[0]) + any_cast<int>(vs[1]);
default: // "Multitive"
return any_cast<int>(vs[0]);
}
};
parser["Multitive"] = [](const SemanticValues &vs) {
switch (vs.choice()) {
case 0: // "Primary '*' Multitive"
return any_cast<int>(vs[0]) * any_cast<int>(vs[1]);
default: // "Primary"
return any_cast<int>(vs[0]);
}
};
parser["Number"] = [](const SemanticValues &vs) {
return vs.token_to_number<int>();
};
// (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<Identifier>(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<ast.nodes.size(); i++) {
eval(cxt, *nodes[i]);
}
return Nil();
} else if (ast.name == "VarDecl") {
auto identifier = any_cast<Identifier>(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<long>();
} else if (ast.name == "BUILTINCALL" ) {
auto identifier = any_cast<Identifier>(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<std::any> exprs;
for (int i=0; i<ast.nodes.size(); i++) {
exprs.push_back(getValue(cxt, eval(cxt, *nodes[i])));
}
return exprs;
} else if (ast.name == "AdditionExpr") {
auto value = getValue(cxt, eval(cxt, *nodes[0]));
for (int i=1; i<nodes.size(); i+=2) {
int op = (*nodes[i]).choice;
auto v2 = getValue(cxt, eval(cxt, *nodes[i+1]));
// TODO: floats
if (op == 0) {
value = any_cast<long>(value) + any_cast<long>(v2);
} else {
value = any_cast<long>(value) - any_cast<long>(v2);
}
}
return value;
} else if (ast.name == "MultiplyExpr") {
auto value = getValue(cxt, eval(cxt, *nodes[0]));
for (int i=1; i<nodes.size(); i+=2) {
int op = (*nodes[i]).choice;
auto v2 = getValue(cxt, eval(cxt, *nodes[i+1]));
// TODO: floats
if (op == 0) {
value = any_cast<long>(value) * any_cast<long>(v2);
} else {
value = any_cast<long>(value) / any_cast<long>(v2);
}
}
return value;
}
std::cout << "AST Name: " << ast.name << std::endl;
for (int i=0; i<ast.nodes.size(); i++) {
std::cout << "AST child: " << ast.name << " : ";
eval(cxt, *nodes[i]);
}
return Nil();
}
int main(void) {
peg::parser parser(
#include "grammar.peg"
@ -147,7 +14,27 @@ int main(void) {
std::string s = R"(
var a = "hello world";
var b = 20 + 10 + 5 - 10 * 2 / 2;
b *= 2;
@print("hello world");
@print(a,b);
b = 2;
@print(b);
a = b != 2;
@print(a);
if (a) {
@print("yay");
} else {
@print("neigh");
}
a = 10;
while(a > 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;
}

View File

@ -6,11 +6,7 @@
Args Args::toArgs(Context& cxt, std::any input) {
Args args;
if (input.type() == typeid(Identifier)) {
auto id = std::any_cast<Identifier>(input);
auto value = cxt.currentScope->getVar(cxt, id.identifier);
args.args.push_back(value);
} else if (input.type() == typeid(std::vector<std::any>)) {
if (input.type() == typeid(std::vector<std::any>)) {
args.args = std::any_cast<std::vector<std::any>>(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; i<args.args.size(); i++) {
cxt.currentScope->writeVar(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<args.args.size(); i++) {
std::any var = args.args[i];
if (var.type() == typeid(long)) {
std::cout << std::any_cast<long>(var) << '\t';
} else if (var.type() == typeid(std::string)) {
std::cout << std::any_cast<std::string>(var) << '\t';
} else if (var.type() == typeid(bool)) {
bool v = std::any_cast<bool>(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();
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <cpp-peglib/peglib.h>
#include <string>
#include <any>
#include <vector>
@ -33,20 +35,29 @@ public:
class Func {
public:
std::shared_ptr<Scope> capturedScope;
// ast ptr
std::function<void(Context&,Args&)> nativeFunction;
std::shared_ptr<peg::Ast> ast = nullptr;
std::vector<Identifier> argNames;
std::function<std::any(Context&,Args&)> nativeFunction;
public:
Func(std::function<void(Context&,Args&)> nativeFunction)
/**
* Create a native function
*/
Func(std::function<std::any(Context&,Args&)> 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<peg::Ast> ast, std::vector<Identifier> 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);
};