aboutsummaryrefslogtreecommitdiffstats
path: root/tuplr.cpp
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2009-03-05 21:04:17 +0000
committerDavid Robillard <d@drobilla.net>2009-03-05 21:04:17 +0000
commit2e7b59ee140e75bb763a90ef10b1d4126822467a (patch)
tree9fab3cfdaafbfd45c2d450da4c7eccb81891a407 /tuplr.cpp
parent43a365c87a017513be9370557ee2cbbad3f0648a (diff)
downloadresp-2e7b59ee140e75bb763a90ef10b1d4126822467a.tar.gz
resp-2e7b59ee140e75bb763a90ef10b1d4126822467a.tar.bz2
resp-2e7b59ee140e75bb763a90ef10b1d4126822467a.zip
Proper error reporting for undefined symbols.
Fix line/col in error messages to point to start of relevant token. git-svn-id: http://svn.drobilla.net/resp/tuplr@48 ad02d1e2-f140-0410-9f75-f8b11f17cedd
Diffstat (limited to 'tuplr.cpp')
-rw-r--r--tuplr.cpp87
1 files changed, 46 insertions, 41 deletions
diff --git a/tuplr.cpp b/tuplr.cpp
index 9920172..e3e439f 100644
--- a/tuplr.cpp
+++ b/tuplr.cpp
@@ -79,35 +79,38 @@ struct Exp { // ::= Atom | (Exp*)
typedef Exp<string> SExp;
static SExp
-readExpression(Cursor& loc, std::istream& in)
+readExpression(Cursor& cur, std::istream& in)
{
#define PUSH(s, t) { if (t != "") { s.top().list.push_back(SExp(loc, t)); t = ""; } }
-#define YIELD(s, t) { if (s.empty()) return SExp(loc, t); else PUSH(s, 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 (char ch = in.get()) {
- ++loc.col;
+ ++cur.col;
switch (ch) {
case EOF:
- if (!stk.empty()) throw Error("unexpected end of file", loc);
- return SExp(loc);
+ if (!stk.empty()) throw Error("unexpected end of file", cur);
+ return SExp(cur);
+ case ';':
+ while ((ch = in.get()) != '\n') {}
case '\n':
- ++loc.line;
- loc.col = 0;
+ ++cur.line; cur.col = 0;
case ' ': case '\t':
if (tok != "") YIELD(stk, tok);
break;
case '"':
- do { tok.push_back(ch); ++loc.col; } while ((ch = in.get()) != '"');
+ loc = cur;
+ do { tok.push_back(ch); ++cur.col; } while ((ch = in.get()) != '"');
YIELD(stk, tok + '"');
break;
case '(':
- stk.push(SExp(loc));
+ stk.push(SExp(cur));
break;
case ')':
switch (stk.size()) {
case 0:
- throw Error("unexpected `)'", loc);
+ throw Error("unexpected `)'", cur);
case 1:
PUSH(stk, tok);
return stk.top();
@@ -119,15 +122,16 @@ readExpression(Cursor& loc, std::istream& in)
}
break;
default:
+ if (tok == "") loc = cur;
tok += ch;
}
}
switch (stk.size()) {
case 0: return SExp(loc, tok);
case 1: return stk.top();
- default: throw Error("missing `)'", loc);
+ default: throw Error("missing `)'", cur);
}
- return SExp(loc);
+ return SExp(cur);
}
@@ -166,10 +170,11 @@ struct ASTLiteral : public AST {
/// Symbol, e.g. "a"
struct ASTSymbol : public AST {
- ASTSymbol(const string& s) : cppstr(s) {}
+ ASTSymbol(const string& s, Cursor c=Cursor()) : loc(c), cppstr(s) {}
bool operator==(const AST& rhs) const { return this == &rhs; }
string str() const { return cppstr; }
Value* compile(CEnv& cenv);
+ Cursor loc;
private:
const string cppstr;
};
@@ -386,11 +391,11 @@ struct PEnv : private map<const string, ASTSymbol*> {
map<string, Parser>::const_iterator i = parsers.find(s);
return (i != parsers.end()) ? &i->second : NULL;
}
- ASTSymbol* sym(const string& s) {
+ ASTSymbol* sym(const string& s, Cursor c=Cursor()) {
const const_iterator i = find(s);
return ((i != end())
? i->second
- : insert(make_pair(s, new ASTSymbol(s))).first->second);
+ : insert(make_pair(s, new ASTSymbol(s, c))).first->second);
}
};
@@ -428,7 +433,7 @@ parseExpression(PEnv& penv, const SExp& exp)
} else if (exp.atom == "false") {
return new ASTLiteral<bool>(false);
}
- return penv.sym(exp.atom);
+ return penv.sym(exp.atom, exp.loc);
}
// Special forms
@@ -825,7 +830,7 @@ Value*
ASTSymbol::compile(CEnv& cenv)
{
AST** c = cenv.code.ref(this);
- if (!c) throw Error((string("undefined symbol `") + cppstr + "'").c_str());
+ if (!c) throw Error((string("undefined symbol `") + cppstr + "'").c_str(), loc);
return cenv.compile(*c);
}
@@ -1152,34 +1157,34 @@ eval(CEnv& cenv, ExecutionEngine* engine, const string& name, istream& is)
if (!resultType || resultType->var()) throw Error("body is undefined/untyped", cursor);
+ // Create function for top-level of program
+ ASTTuple prot;
+ const Type* ctype = resultType->type();
+ if (!ctype) {
+ err << "program body has non-compilable type" << endl;
+ return 2;
+ }
+ assert(ctype);
+ Function* f = compileFunction(cenv, cenv.gensym("input"), ctype, prot);
+ BasicBlock* bb = BasicBlock::Create("entry", f);
+ cenv.builder.SetInsertPoint(bb);
+
+ // Compile all expressions into it
+ Value* val = NULL;
+ for (list< pair<SExp, AST*> >::const_iterator i = exprs.begin(); i != exprs.end(); ++i)
+ val = cenv.compile(i->second);
+
+ // Finish function
+ cenv.builder.CreateRet(val);
+ cenv.optimise(*f);
+
+ string resultStr = call(resultType, engine->getPointerToFunction(f));
+ out << resultStr << " : " << resultType->str() << endl;
+
} catch (Error& e) {
err << e.what() << endl;
return 1;
}
-
- // Create function for top-level of program
- ASTTuple prot;
- const Type* ctype = resultType->type();
- if (!ctype) {
- err << "program body has non-compilable type" << endl;
- return 2;
- }
- assert(ctype);
- Function* f = compileFunction(cenv, cenv.gensym("input"), ctype, prot);
- BasicBlock* bb = BasicBlock::Create("entry", f);
- cenv.builder.SetInsertPoint(bb);
-
- // Compile all expressions into it
- Value* val = NULL;
- for (list< pair<SExp, AST*> >::const_iterator i = exprs.begin(); i != exprs.end(); ++i)
- val = cenv.compile(i->second);
-
- // Finish function
- cenv.builder.CreateRet(val);
- cenv.optimise(*f);
-
- string resultStr = call(resultType, engine->getPointerToFunction(f));
- out << resultStr << " : " << resultType->str() << endl;
return 0;
}