aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--src/lex.cpp95
-rw-r--r--src/parse.cpp131
-rw-r--r--src/tuplr.cpp182
-rw-r--r--src/tuplr.hpp7
-rw-r--r--tuplr.dox3
6 files changed, 234 insertions, 186 deletions
diff --git a/Makefile b/Makefile
index f91718e..9388f95 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,9 @@ OBJECTS = \
build/cps.o \
build/gc.o \
build/gclib.so \
+ build/lex.o \
build/llvm.so \
+ build/parse.o \
build/pprint.o \
build/tuplr.o \
build/unify.o
diff --git a/src/lex.cpp b/src/lex.cpp
new file mode 100644
index 0000000..81dbe19
--- /dev/null
+++ b/src/lex.cpp
@@ -0,0 +1,95 @@
+/* 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 Lexing (build a SExp from a string)
+ */
+
+#include <stack>
+#include "tuplr.hpp"
+
+using namespace std;
+
+inline int
+readChar(Cursor& cur, istream& in)
+{
+ int ch = in.get();
+ switch (ch) {
+ case '\n': ++cur.line; cur.col = 0; break;
+ default: ++cur.col;
+ }
+ return ch;
+}
+
+SExp
+readExpression(Cursor& cur, istream& in)
+{
+#define PUSH(s, t) { if (t != "") { s.top().push_back(SExp(loc, t)); t = ""; } }
+#define YIELD(s, t) { if (s.empty()) { return SExp(loc, t); } else PUSH(s, t) }
+ stack<SExp> stk;
+ string tok;
+ Cursor loc; // start of tok
+ while (int c = readChar(cur, in)) {
+ switch (c) {
+ case EOF:
+ THROW_IF(!stk.empty(), cur, "unexpected end of file")
+ return SExp(cur);
+ case ';':
+ while ((c = readChar(cur, in)) != '\n') {}
+ case '\n': case ' ': case '\t':
+ if (tok != "") YIELD(stk, tok);
+ break;
+ case '"':
+ loc = cur;
+ do { tok.push_back(c); } while ((c = readChar(cur, in)) != '"');
+ YIELD(stk, tok + '"');
+ break;
+ case '(':
+ stk.push(SExp(cur));
+ break;
+ case ')':
+ switch (stk.size()) {
+ case 0:
+ throw Error(cur, "unexpected `)'");
+ case 1:
+ PUSH(stk, tok);
+ return stk.top();
+ default:
+ PUSH(stk, tok);
+ SExp l = stk.top();
+ stk.pop();
+ stk.top().push_back(l);
+ }
+ break;
+ case '#':
+ if (in.peek() == '|') {
+ while (!(readChar(cur, in) == '|' && readChar(cur, in) == '#')) {}
+ break;
+ }
+ default:
+ if (tok == "") loc = cur;
+ tok += c;
+ }
+ }
+ switch (stk.size()) {
+ case 0: return SExp(loc, tok);
+ case 1: return stk.top();
+ default: throw Error(cur, "missing `)'");
+ }
+ return SExp(cur);
+}
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>));
+}
diff --git a/src/tuplr.cpp b/src/tuplr.cpp
index 7ff9f52..a0c001d 100644
--- a/src/tuplr.cpp
+++ b/src/tuplr.cpp
@@ -24,7 +24,6 @@
#include <fstream>
#include <set>
#include <sstream>
-#include <stack>
#include "tuplr.hpp"
using namespace std;
@@ -52,187 +51,6 @@ operator<<(ostream& out, const Exp<Atom>& exp)
/***************************************************************************
- * Lexer *
- ***************************************************************************/
-
-inline int
-readChar(Cursor& cur, istream& in)
-{
- int ch = in.get();
- switch (ch) {
- case '\n': ++cur.line; cur.col = 0; break;
- default: ++cur.col;
- }
- return ch;
-}
-
-SExp
-readExpression(Cursor& cur, istream& in)
-{
-#define PUSH(s, t) { if (t != "") { s.top().push_back(SExp(loc, t)); t = ""; } }
-#define YIELD(s, t) { if (s.empty()) { return SExp(loc, t); } else PUSH(s, t) }
- stack<SExp> stk;
- string tok;
- Cursor loc; // start of tok
- while (int c = readChar(cur, in)) {
- switch (c) {
- case EOF:
- THROW_IF(!stk.empty(), cur, "unexpected end of file")
- return SExp(cur);
- case ';':
- while ((c = readChar(cur, in)) != '\n') {}
- case '\n': case ' ': case '\t':
- if (tok != "") YIELD(stk, tok);
- break;
- case '"':
- loc = cur;
- do { tok.push_back(c); } while ((c = readChar(cur, in)) != '"');
- YIELD(stk, tok + '"');
- break;
- case '(':
- stk.push(SExp(cur));
- break;
- case ')':
- switch (stk.size()) {
- case 0:
- throw Error(cur, "unexpected `)'");
- case 1:
- PUSH(stk, tok);
- return stk.top();
- default:
- PUSH(stk, tok);
- SExp l = stk.top();
- stk.pop();
- stk.top().push_back(l);
- }
- break;
- case '#':
- if (in.peek() == '|') {
- while (!(readChar(cur, in) == '|' && readChar(cur, in) == '#')) {}
- break;
- }
- default:
- if (tok == "") loc = cur;
- tok += c;
- }
- }
- switch (stk.size()) {
- case 0: return SExp(loc, tok);
- case 1: return stk.top();
- default: throw Error(cur, "missing `)'");
- }
- return SExp(cur);
-}
-
-
-/***************************************************************************
- * 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;
-}
-
-
-/***************************************************************************
- * Standard Definitions *
- ***************************************************************************/
-
-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>));
-}
-
-
-/***************************************************************************
* EVAL/REPL *
***************************************************************************/
diff --git a/src/tuplr.hpp b/src/tuplr.hpp
index 613be0d..4948b82 100644
--- a/src/tuplr.hpp
+++ b/src/tuplr.hpp
@@ -138,11 +138,12 @@ typedef void* CFunction; ///< Compiled function (opaque)
/***************************************************************************
- * Garbage Collector *
+ * Garbage Collection *
***************************************************************************/
-struct Object; ///< Object (AST nodes and runtime data)
+struct Object;
+/// Garbage collector
struct GC {
enum Tag {
TAG_AST = 2, ///< Abstract syntax tree node
@@ -160,7 +161,7 @@ private:
Roots _roots;
};
-/// Dynamic (garbage-collected) object
+/// Garbage collected object (including AST and runtime data)
struct Object {
struct Header {
uint8_t mark;
diff --git a/tuplr.dox b/tuplr.dox
index 01e4390..456d159 100644
--- a/tuplr.dox
+++ b/tuplr.dox
@@ -297,7 +297,7 @@ SYMBOL_CACHE_SIZE = 0
# Private class members and static file members will be hidden unless
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-EXTRACT_ALL = NO
+EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
@@ -568,6 +568,7 @@ INPUT = src/constrain.cpp \
src/cps.cpp \
src/gc.cpp \
src/gclib.cpp \
+ src/lex.cpp \
src/llvm.cpp \
src/pprint.cpp \
src/tuplr.cpp \