Permalink
Browse files

Make modules just an expression at the top level.

No more hacky ModuleAst stuff. Just a single expression.
Also fix a bug with lexing a // comment at the end of a file.
  • Loading branch information...
1 parent 583696d commit 31d2f17c6793b7c7e1d101d03825cd98486d102a @munificent committed May 4, 2012
View
@@ -1,40 +1,30 @@
#include "Compiler.h"
#include "ErrorReporter.h"
#include "Method.h"
+#include "Module.h"
#include "Node.h"
#include "Object.h"
#include "VM.h"
namespace magpie
{
- void Compiler::compileModule(VM& vm, gc<ModuleAst> module,
- ErrorReporter& reporter)
+ Module* Compiler::compileModule(VM& vm, gc<Node> module,
+ ErrorReporter& reporter)
{
- // Declare methods first so we can resolve mutually recursive calls.
- for (int i = 0; i < module->methods().count(); i++)
- {
- const DefMethodNode& methodAst = *module->methods()[i]->asDefMethodNode();
- vm.methods().declare(methodAst.name());
- }
+ // TODO(bob): Temp hackish. Wrap the module body in a fake method.
+ DefMethodNode* method = new DefMethodNode(module->pos(),
+ String::create("<module>"),
+ new VariablePattern(String::create("<unused>")), module);
- // Try to compile all of the methods.
- for (int i = 0; i < module->methods().count(); i++)
- {
- const DefMethodNode& methodAst = *module->methods()[i]->asDefMethodNode();
- gc<Method> method = compileMethod(vm, methodAst, reporter);
-
- // Bail if there was a compile error.
- if (method.isNull()) return;
-
- vm.methods().define(methodAst.name(), method);
- }
+ gc<Method> body = compileMethod(vm, *method, reporter);
+ return new Module(body);
}
- gc<Method> Compiler::compileMethod(VM& vm, const DefMethodNode& methodAst,
+ gc<Method> Compiler::compileMethod(VM& vm, const DefMethodNode& method,
ErrorReporter& reporter)
{
Compiler compiler(vm, reporter);
- return compiler.compile(methodAst);
+ return compiler.compile(method);
}
Compiler::Compiler(VM& vm, ErrorReporter& reporter)
View
@@ -9,17 +9,17 @@ namespace magpie
{
class ErrorReporter;
class Method;
- class MethodAst;
- class ModuleAst;
+ class Module;
+ class Node;
class Object;
class VM;
class Compiler : private NodeVisitor, private PatternVisitor
{
public:
- static void compileModule(VM& vm, gc<ModuleAst> module,
- ErrorReporter& reporter);
- static gc<Method> compileMethod(VM& vm, const DefMethodNode& methodAst,
+ static Module* compileModule(VM& vm, gc<Node> module,
+ ErrorReporter& reporter);
+ static gc<Method> compileMethod(VM& vm, const DefMethodNode& method,
ErrorReporter& reporter);
virtual ~Compiler() {}
View
@@ -209,8 +209,7 @@ namespace magpie
void Lexer::skipLineComment()
{
- // TODO(bob): Handle EOF.
- while (peek() != '\n') advance();
+ while (!isDone() && peek() != '\n') advance();
}
void Lexer::skipBlockComment()
View
@@ -2,15 +2,6 @@
namespace magpie
{
- ModuleAst::ModuleAst(Array<gc<Node> >& methods)
- : methods_(methods)
- {}
-
- void ModuleAst::reach()
- {
- Memory::reach(methods_);
- }
-
void AndNode::trace(std::ostream& out) const
{
out << "(and " << left_ << " " << right_ << ")";
View
@@ -37,18 +37,6 @@ namespace magpie
NO_COPY(PatternVisitor);
};
- class ModuleAst : public Managed
- {
- public:
- ModuleAst(Array<gc<Node> >& methods);
-
- const Array<gc<Node> > methods() const { return methods_; }
-
- virtual void reach();
- private:
- Array<gc<Node> > methods_;
- };
-
#include "Node.generated.h"
// Base class for all AST pattern node classes.
View
@@ -55,41 +55,21 @@ namespace magpie
{ NULL, NULL, -1 } // TOKEN_EOF
};
- gc<ModuleAst> Parser::parseModule()
+ gc<Node> Parser::parseModule()
{
- Array<gc<Node> > methods;
+ Array<gc<Node> > exprs;
do
{
if (lookAhead(TOKEN_EOF)) break;
-
- // Method definition.
- SourcePos start = current().pos();
- consume(TOKEN_DEF, "The top level of a module contains only method definitions.");
- gc<Token> name = consume(TOKEN_NAME,
- "Expect a method name after 'def'.");
-
- // TODO(bob): Parse real pattern(s).
- gc<Pattern> pattern = NULL;
- consume(TOKEN_LEFT_PAREN, "Temp.");
- if (lookAhead(TOKEN_NAME))
- {
- pattern = parsePattern();
- }
- consume(TOKEN_RIGHT_PAREN, "Temp.");
-
- gc<Node> body = parseBlock();
-
- SourcePos span = start.spanTo(current().pos());
- methods.add(new DefMethodNode(span, name->text(), pattern, body));
+ exprs.add(statementLike());
}
while (match(TOKEN_LINE));
// TODO(bob): Should validate that we are at EOF here.
-
- return new ModuleAst(methods);
+ return createSequence(exprs);
}
-
+
gc<Node> Parser::parseBlock(TokenType endToken)
{
TokenType dummy;
@@ -122,11 +102,7 @@ namespace magpie
// single-expression block case.
if (current().is(TOKEN_END)) consume();
- // If there is just one expression in the sequence, don't wrap it.
- if (exprs.count() == 1) return exprs[0];
-
- SourcePos span = exprs[0]->pos().spanTo(current().pos());
- return new SequenceNode(span, exprs);
+ return createSequence(exprs);
}
else
{
@@ -226,7 +202,6 @@ namespace magpie
while (precedence < expressions_[current().type()].precedence)
{
token = consume();
-
InfixParseFn infix = expressions_[token->type()].infix;
left = (this->*infix)(left, token);
}
@@ -318,6 +293,17 @@ namespace magpie
}
}
+ gc<Node> Parser::createSequence(const Array<gc<Node> >& exprs)
+ {
+ // If there is just one expression in the sequence, don't wrap it.
+ if (exprs.count() == 1) return exprs[0];
+
+ // TODO(bob): Using current() here and elsewhere is wrong. That's one
+ // token past the span.
+ SourcePos span = exprs[0]->pos().spanTo(exprs[-1]->pos());
+ return new SequenceNode(span, exprs);
+ }
+
const Token& Parser::current()
{
fillLookAhead(1);
View
@@ -22,7 +22,7 @@ namespace magpie
reporter_(reporter)
{}
- gc<ModuleAst> parseModule();
+ gc<Node> parseModule();
private:
typedef gc<Node> (Parser::*PrefixParseFn)(gc<Token> token);
@@ -58,6 +58,8 @@ namespace magpie
gc<Pattern> parsePattern();
gc<Pattern> variablePattern();
+ gc<Node> createSequence(const Array<gc<Node> >& exprs);
+
// Gets the Token the parser is currently looking at.
const Token& current();
View
@@ -18,7 +18,7 @@ namespace magpie
ASSERT(callFrames_.count() == 0, "Cannot re-initialize Fiber.");
// TODO(bob): What should the arg object be here?
- call(method, 0, gc<Object>());
+ call(method, 0, vm_.nothing());
}
gc<Object> Fiber::run()
View
@@ -11,9 +11,19 @@ namespace magpie
class Module
{
public:
+ Module(gc<Method> body)
+ : body_(body)
+ {}
+
void reach();
- private:
+ gc<Method> body() const { return body_; }
+
+ private:
+ // The code comprosing a module is compiled to a fake method, so that
+ // loading a module is basically just executing a function call.
+ gc<Method> body_;
+
NO_COPY(Module);
};
}
View
@@ -23,9 +23,10 @@ namespace magpie
nothing_ = new NothingObject();
}
- gc<Object> VM::run()
+ void VM::loadModule(Module* module)
{
- fiber_->init(methods_.findMain());
+ modules_.add(module);
+ fiber_->init(module->body());
while (true)
{
@@ -34,10 +35,10 @@ namespace magpie
// If the fiber returns null, it's still running but it did a GC run.
// Since that moves the fiber, we return back to here so we can invoke
// run() again at its new location in memory.
- if (!result.isNull()) return result;
+ if (!result.isNull()) return;
}
}
-
+
void VM::reachRoots()
{
methods_.reach();
View
@@ -17,7 +17,7 @@ namespace magpie
public:
VM();
- gc<Object> run();
+ void loadModule(Module* module);
virtual void reachRoots();
@@ -26,6 +26,8 @@ namespace magpie
// The globally available top-level methods.
MethodScope& methods() { return methods_; }
+ inline gc<Object> nothing() const { return nothing_; }
+
inline gc<Object> getBool(bool value) const
{
return value ? true_ : false_;
View
@@ -56,17 +56,16 @@ int main(int argc, char * const argv[])
ErrorReporter reporter;
gc<String> source = readFile(fileName);
Parser parser(fileName, source, reporter);
- gc<ModuleAst> module = parser.parseModule();
+ gc<Node> moduleAst = parser.parseModule();
if (reporter.numErrors() > 0) return 1;
// Compile it.
- Compiler::compileModule(vm, module, reporter);
+ Module* module = Compiler::compileModule(vm, moduleAst, reporter);
if (reporter.numErrors() > 0) return 1;
- // Invoke main().
- vm.run();
+ vm.loadModule(module);
return 0;
}
View
@@ -1,34 +1,32 @@
-def main()
- // Note: These tests implicitly depend on non-zero ints being truthy.
- // Also rely on print() returning its argument.
+// Note: These tests implicitly depend on non-zero ints being truthy.
+// Also rely on print() returning its argument.
- // Return the first non-true argument.
- print(0 and false) // expect: 0
- print(1 and 0) // expect: 0
- print(1 and 2 and 0) // expect: 0
+// Return the first non-true argument.
+print(0 and false) // expect: 0
+print(1 and 0) // expect: 0
+print(1 and 2 and 0) // expect: 0
- // Return the last argument if all are true.
- print(1 and true) // expect: true
- print(1 and 2 and 3) // expect: 3
+// Return the last argument if all are true.
+print(1 and true) // expect: true
+print(1 and 2 and 3) // expect: 3
- // Short-circuit at the first false argument.
- print(true) and // expect: true
- print(false) and // expect: false
- print(false) // should not print
+// Short-circuit at the first false argument.
+print(true) and // expect: true
+ print(false) and // expect: false
+ print(false) // should not print
- // Call 'true?' on the arguments to determine truthiness.
- // TODO(bob): Support this.
- /*
- it should("call 'true?' on the arguments to determine truth") with
- val left = TruthTest new(false)
- val right = TruthTest new(false)
- left and right
- left called shouldEqual(true)
- right called shouldEqual(false)
- end
- */
+// Call 'true?' on the arguments to determine truthiness.
+// TODO(bob): Support this.
+/*
+ it should("call 'true?' on the arguments to determine truth") with
+ val left = TruthTest new(false)
+ val right = TruthTest new(false)
+ left and right
+ left called shouldEqual(true)
+ right called shouldEqual(false)
+ end
+*/
- // Swallow a trailing newline.
- print(true and
- true) // expect: true
-end
+// Swallow a trailing newline.
+print(true and
+ true) // expect: true
@@ -0,0 +1,2 @@
+print("ok") // expect: ok
+/* comment */
@@ -0,0 +1,2 @@
+print("ok") // expect: ok
+// comment
Oops, something went wrong.

0 comments on commit 31d2f17

Please sign in to comment.