Browse Source

Merge pull request #26 from vladfolts/rel_v1.0

Rel v1.0
vladfolts 11 years ago
parent
commit
55b39894a2
3 changed files with 70 additions and 49 deletions
  1. 4 4
      src/grammar.js
  2. 52 43
      src/parser.js
  3. 14 2
      test/test_unit.js

+ 4 - 4
src/grammar.js

@@ -147,7 +147,7 @@ var fpSection = and(optional(literal("VAR")), ident, repeat(and(",", ident)), ":
 var formalParameters = and(
           "("
         , optional(context(and(fpSection, repeat(and(";", fpSection))), Context.ProcParams))
-        , ")"
+        , required( ")" )
         , optional(and(":", qualident)));
 
 var procedureType = and("PROCEDURE"
@@ -168,9 +168,9 @@ var procedureDeclaration = context(
 
 var constantDeclaration = context(and(identdef, "=", constExpression), Context.ConstDecl);
 
-var declarationSequence = and(optional(and("CONST", repeat(and(constantDeclaration, ";"))))
-                            , optional(and("TYPE", context(repeat(and(typeDeclaration, ";")), Context.TypeSection)))
-                            , optional(and("VAR", repeat(and(variableDeclaration, ";"))))
+var declarationSequence = and(optional(and("CONST", repeat(and(constantDeclaration, required(";")))))
+                            , optional(and("TYPE", context(repeat(and(typeDeclaration, required(";"))), Context.TypeSection)))
+                            , optional(and("VAR", repeat(and(variableDeclaration, required(";")))))
                             , repeat(and(procedureDeclaration, ";")));
 var procedureBody = and(declarationSequence
                       , optional(and("BEGIN", statementSequence))

+ 52 - 43
src/parser.js

@@ -1,45 +1,52 @@
+"use strict";
+
 var assert = require("assert.js").ok;
 var Errors = require("errors.js");
 var Lexer = require("lexer.js");
 
+function implicitParser(p){
+	return typeof p === "string" ? Lexer.literal(p) : p;
+}
+
+function argumentsToParsers(args){
+	var parsers = Array.prototype.slice.call(args);
+	for(var i = 0; i < parsers.length; ++i)
+		parsers[i] = implicitParser(parsers[i]);
+	return parsers;
+}
+
 exports.and = function(/*...*/){
-	var args = arguments;
-	assert(args.length >= 2);
+	assert(arguments.length >= 2);
+	var parsers = argumentsToParsers(arguments);
 
 	return function(stream, context){
-		for(var i = 0; i < args.length; ++i){
-			if (i != 0)
+		for(var i = 0; i < parsers.length; ++i){
+			if (i)
 				Lexer.skipSpaces(stream, context);
 			
-			var p = args[i];
-			if (typeof p == "string")
-				p = Lexer.literal(p);
-			
+			var p = parsers[i];
 			if (!p(stream, context))
 				return false;
 		}
-	 	return true;
-	}
-}
+		return true;
+	};
+};
 
 exports.or = function(/*...*/){
-	var args = arguments;
-	assert(args.length >= 2);
+	assert(arguments.length >= 2);
+	var parsers = argumentsToParsers(arguments);
 
 	return function(stream, context){
-		for(var i = 0; i < args.length; ++i){
-			var p = args[i];
-			if (typeof p == "string")
-				p = Lexer.literal(p);
-			
+		for(var i = 0; i < parsers.length; ++i){
+			var p = parsers[i];
 			var savePos = stream.pos();
 			if (p(stream, context))
 				return true;
 			stream.setPos(savePos);
 		}
 		return false;
-	}
-}
+	};
+};
 
 exports.repeat = function(p){
 	return function(stream, context){
@@ -50,50 +57,52 @@ exports.repeat = function(p){
 			}
 			stream.setPos(savePos);
 			return true;
-		}
-}
+		};
+};
 
-exports.optional = function(p){
+exports.optional = function(parser){
 	assert(arguments.length == 1);
-	if (typeof(p) === "string")
-		p = Lexer.literal(p);
+	var p = implicitParser(parser);
+
 	return function(stream, context){
 		var savePos = stream.pos();
 		if ( !p(stream, context))
 			stream.setPos(savePos);
 		return true;
-		}
-}
+		};
+};
 
-exports.required = function(parser, error){
-	if (typeof(parser) === "string")
-		parser = Lexer.literal(parser);
+exports.required = function(parserOrString, error){
+	var parser = implicitParser(parserOrString);
+	
 	return function(stream, context){
 		if (!parser(stream, context))
-			throw new Errors.Error(error);
+			throw new Errors.Error(error 
+					? error 
+					: ("'" + parserOrString + "' expected"));
 		return true;
-	}
-}
+	};
+};
 
-exports.context = function(parser, contextFactory){
-	return function(stream, context){
-		var context = new contextFactory(context);
+exports.context = function(parser, ContextFactory){
+	return function(stream, child){
+		var context = new ContextFactory(child);
 		if (!parser(stream, context))
 			return false;
 		if (context.endParse)
 			return context.endParse() !== false;
 		return true;
-	}
-}
+	};
+};
 
 exports.emit = function(parser, action){
 	assert(action);
-	if (typeof(parser) === "string")
-		parser = Lexer.literal(parser);
+	var p = implicitParser(parser);
+
 	return function(stream, context){
-		if (!parser(stream, context))
+		if (!p(stream, context))
 			return false;
 		action(context);
 		return true;
-	}
-}
+	};
+};

+ 14 - 2
test/test_unit.js

@@ -1151,7 +1151,7 @@ var testSuite = {
          "PROCEDURE p(a: ARRAY OF A); BEGIN END p"
         ),
     fail(["PROCEDURE p(a: ARRAY OF ARRAY 3 OF INTEGER); BEGIN END p",
-          "not parsed"]
+          "')' expected"]
         )
     ),
 "non-open array type as procedure parameter": testWithContext(
@@ -1165,7 +1165,7 @@ var testSuite = {
          "PROCEDURE p(); VAR a: ARRAY 2 OF INTEGER; BEGIN pa(a) END p"
          ),
     fail(["PROCEDURE p(a: ARRAY 3 OF INTEGER); BEGIN END p",
-          "not parsed"],
+          "')' expected"],
          ["PROCEDURE p(a: A): INTEGER; BEGIN RETURN a[2] END p",
           "index out of bounds: maximum possible index is 1, got 2"],
          ["PROCEDURE p(); VAR a: ARRAY 1 OF INTEGER; BEGIN pa(a) END p",
@@ -1318,6 +1318,18 @@ var testSuite = {
     pass(),
     fail(["MODULE m; IMPORT test; BEGIN ASSERT(test.p.i = 0) END m.",
           "non-exported RECORD type cannot be dereferenced"])
+    ),
+"syntax errors": testWithGrammar(
+    Grammar.module,
+    pass(),
+    fail(["MODULE m; CONST c = 1 END m.",
+          "';' expected"],
+         ["MODULE m; TYPE T = RECORD END END m.",
+          "';' expected"],
+         ["MODULE m; VAR v: INTEGER END m.",
+          "';' expected"],
+         ["MODULE m; PROCEDURE p(INTEGER) END m.",
+          "')' expected"])
     )
 };