From bffe49291e9709b5bfc960420fcc6f5a4b1614bd Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Sat, 12 Feb 2011 22:27:59 -0800 Subject: [PATCH] Parse and evaluate files incrementally. This minor change has a big semantic effect. Top-level xpressions in a file will now be *evaluated* before subsequent expressions are *parsed*. This allows expressions that define parsers (or import them) to affect the parsing of the rest of the file. --- src/com/stuffwithstuff/magpie/Script.java | 12 ++++++++++-- .../magpie/interpreter/Interpreter.java | 17 +++++++---------- .../interpreter/builtin/RuntimeBuiltIns.java | 13 +------------ .../magpie/parser/MagpieParser.java | 19 ++++++------------- 4 files changed, 24 insertions(+), 37 deletions(-) diff --git a/src/com/stuffwithstuff/magpie/Script.java b/src/com/stuffwithstuff/magpie/Script.java index aa83cfa8..967cbb07 100644 --- a/src/com/stuffwithstuff/magpie/Script.java +++ b/src/com/stuffwithstuff/magpie/Script.java @@ -8,6 +8,7 @@ import java.nio.charset.Charset; import java.util.List; +import com.stuffwithstuff.magpie.ast.Expr; import com.stuffwithstuff.magpie.interpreter.CheckError; import com.stuffwithstuff.magpie.interpreter.Checker; import com.stuffwithstuff.magpie.interpreter.Interpreter; @@ -44,8 +45,15 @@ public void execute(Interpreter interpreter) { Lexer lexer = new Lexer(mPath, new StringCharacterReader(mText)); MagpieParser parser = interpreter.createParser(lexer); - interpreter.load(parser.parse()); - + // Evaluate every expression in the file. We do this incrementally so + // that expressions that define parsers can be used to parse the rest of + // the file. + while (true) { + Expr expr = parser.parseTopLevelExpression(); + if (expr == null) break; + interpreter.interpret(expr); + } + // If there is a main() function, then we need to type-check first: if (interpreter.hasMain()) { // Do the static analysis and see if we got the errors we expect. diff --git a/src/com/stuffwithstuff/magpie/interpreter/Interpreter.java b/src/com/stuffwithstuff/magpie/interpreter/Interpreter.java index 636bbdf2..e1ca2112 100644 --- a/src/com/stuffwithstuff/magpie/interpreter/Interpreter.java +++ b/src/com/stuffwithstuff/magpie/interpreter/Interpreter.java @@ -131,20 +131,17 @@ public Interpreter(InterpreterHost host) { EnvironmentBuilder.initialize(this); } - public void load(List expressions) { + public void interpret(Expr expression) { EvalContext context = createTopLevelContext(); - // Evaluate the expressions. This is the load time evaluation. - for (Expr expr : expressions) { - try { - evaluate(expr, context); - } catch(ErrorException err) { - // TODO(bob): Better error message here! - mHost.runtimeError(expr.getPosition(), "Uncaught error."); - } + try { + evaluate(expression, context); + } catch(ErrorException err) { + // TODO(bob): Better error message here! + mHost.runtimeError(expression.getPosition(), "Uncaught error."); } } - + public Obj evaluate(Expr expr) { return evaluate(expr, createTopLevelContext()); } diff --git a/src/com/stuffwithstuff/magpie/interpreter/builtin/RuntimeBuiltIns.java b/src/com/stuffwithstuff/magpie/interpreter/builtin/RuntimeBuiltIns.java index 75525a90..25b91cd0 100644 --- a/src/com/stuffwithstuff/magpie/interpreter/builtin/RuntimeBuiltIns.java +++ b/src/com/stuffwithstuff/magpie/interpreter/builtin/RuntimeBuiltIns.java @@ -5,7 +5,6 @@ import java.util.List; import com.stuffwithstuff.magpie.Script; -import com.stuffwithstuff.magpie.ast.BlockExpr; import com.stuffwithstuff.magpie.ast.Expr; import com.stuffwithstuff.magpie.interpreter.CheckError; import com.stuffwithstuff.magpie.interpreter.Checker; @@ -91,18 +90,8 @@ public Obj invoke(Interpreter interpreter, Obj thisObj, Obj arg) { e.printStackTrace(); } - // Pull out the list of expressions. If it's a BlockExpr, we do this so that - // it doesn't evaluate the body in a nested scope. - List exprs; - if (expr instanceof BlockExpr) { - exprs = ((BlockExpr)expr).getExpressions(); - } else { - exprs = new ArrayList(); - exprs.add(expr); - } + inner.interpret(expr); - inner.load(exprs); - // Do the static analysis and see if we got the errors we expect. Checker checker = new Checker(inner); checker.checkAll(); diff --git a/src/com/stuffwithstuff/magpie/parser/MagpieParser.java b/src/com/stuffwithstuff/magpie/parser/MagpieParser.java index 335dbd91..e8e9c13a 100644 --- a/src/com/stuffwithstuff/magpie/parser/MagpieParser.java +++ b/src/com/stuffwithstuff/magpie/parser/MagpieParser.java @@ -78,19 +78,12 @@ public MagpieParser(Lexer lexer) { this(lexer, null, null, null); } - public List parse() { - // Parse the entire file. - List expressions = new ArrayList(); - do { - expressions.add(parseExpression()); - - // Allow files with no trailing newline. - if (match(TokenType.EOF)) break; - - consume(TokenType.LINE); - } while (!match(TokenType.EOF)); - - return expressions; + public Expr parseTopLevelExpression() { + if (lookAhead(TokenType.EOF)) return null; + + Expr expr = parseExpression(); + if (!lookAhead(TokenType.EOF)) consume(TokenType.LINE); + return expr; } public Expr parseExpression(int stickiness) {