diff options
Diffstat (limited to 'src/parse.cpp')
-rw-r--r-- | src/parse.cpp | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/parse.cpp b/src/parse.cpp new file mode 100644 index 0000000..ae34778 --- /dev/null +++ b/src/parse.cpp @@ -0,0 +1,131 @@ +/* Tuplr: A programming language + * Copyright (C) 2008-2009 David Robillard <dave@drobilla.net> + * + * Tuplr is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Tuplr 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 Affero General + * Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Tuplr. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file + * @brief Parsing (build an AST from a SExp) + */ + +#include "tuplr.hpp" + +using namespace std; + + +/*************************************************************************** + * Macro Functions * + ***************************************************************************/ + +inline SExp +macDef(PEnv& penv, const SExp& exp) +{ + THROW_IF(exp.size() < 3, exp.loc, "[MAC] `def' requires at least 2 arguments") + if (exp.at(1).type == SExp::ATOM) { + return exp; + } else { + // (def (f x) y) => (def f (fn (x) y)) + SExp argsExp(exp.loc); + for (size_t i = 1; i < exp.at(1).size(); ++i) + argsExp.push_back(exp.at(1).at(i)); + SExp fnExp(exp.at(2).loc); + fnExp.push_back(SExp(exp.at(2).loc, "fn")); + fnExp.push_back(argsExp); + for (size_t i = 2; i < exp.size(); ++i) + fnExp.push_back(exp.at(i)); + SExp ret(exp.loc); + ret.push_back(exp.at(0)); + ret.push_back(exp.at(1).at(0)); + ret.push_back(fnExp); + return ret; + } +} + + +/*************************************************************************** + * Parser Functions * + ***************************************************************************/ + +template<typename C> +inline AST* +parseCall(PEnv& penv, const SExp& exp, void* arg) +{ + return new C(exp, penv.parseTuple(exp)); +} + +template<typename T> +inline AST* +parseLiteral(PEnv& penv, const SExp& exp, void* arg) +{ + return new ALiteral<T>(*reinterpret_cast<T*>(arg), exp.loc); +} + +inline AST* +parseFn(PEnv& penv, const SExp& exp, void* arg) +{ + if (exp.size() < 2) + throw Error(exp.loc, "Missing function parameters and body"); + else if (exp.size() < 3) + throw Error(exp.loc, "Missing function body"); + SExp::const_iterator a = exp.begin(); ++a; + AFn* ret = tup<AFn>(exp.loc, penv.sym("fn"), new ATuple(penv.parseTuple(*a++)), 0); + while (a != exp.end()) + ret->push_back(penv.parse(*a++)); + return ret; +} + + +/*************************************************************************** + * Language Definition * + ***************************************************************************/ + +void +initLang(PEnv& penv, TEnv& tenv) +{ + // Types + tenv.def(penv.sym("Nothing"), make_pair((AST*)0, new AType(penv.sym("Nothing")))); + tenv.def(penv.sym("Bool"), make_pair((AST*)0, new AType(penv.sym("Bool")))); + tenv.def(penv.sym("Int"), make_pair((AST*)0, new AType(penv.sym("Int")))); + tenv.def(penv.sym("Float"), make_pair((AST*)0, new AType(penv.sym("Float")))); + + // Literals + static bool trueVal = true; + static bool falseVal = false; + penv.reg(false, "#t", PEnv::Handler(parseLiteral<bool>, &trueVal)); + penv.reg(false, "#f", PEnv::Handler(parseLiteral<bool>, &falseVal)); + + // Macros + penv.defmac("def", macDef); + + // Special forms + penv.reg(true, "fn", PEnv::Handler(parseFn)); + penv.reg(true, "if", PEnv::Handler(parseCall<AIf>)); + penv.reg(true, "def", PEnv::Handler(parseCall<ADef>)); + + // Numeric primitives + penv.reg(true, "+", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, "-", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, "*", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, "/", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, "%", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, "and", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, "or", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, "xor", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, "=", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, "!=", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, ">", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, ">=", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, "<", PEnv::Handler(parseCall<APrimitive>)); + penv.reg(true, "<=", PEnv::Handler(parseCall<APrimitive>)); +} |