Ver código fonte

js -> eberon transition

Vladislav Folts 10 anos atrás
pai
commit
b52049bece

BIN
bin/compiled.zip


+ 1 - 1
build.py

@@ -127,7 +127,7 @@ def run_tests(bin, unit_test=None, code_test=None):
 def recompile(bin):
     print('recompile oberon sources using "%s"...' % bin)
     compiler = os.path.join(root, 'src', 'oc_nodejs.js')
-    sources = ['ContextCase.ob', 'ContextConst.ob', 'ContextIdentdef', 'ContextIf', 'ContextProcedure.ob', 'EberonSymbols.ob', 'EberonCast.ob', 
+    sources = ['ContextCase.ob', 'ContextConst.ob', 'ContextIdentdef', 'ContextLoop', 'ContextProcedure.ob', 'EberonSymbols.ob', 'EberonCast.ob', 
                'EberonConstructor.ob', 'EberonOperator.ob', 'EberonScope.ob',
                'OberonSymbols.ob', 'Lexer.ob', 'Module.ob']
     

+ 0 - 134
src/context.js

@@ -42,140 +42,6 @@ var HandleSymbolAsType = ContextType.HandleSymbolAsType;
 HandleSymbolAsType.extend = Class.extend;
 HandleSymbolAsType.prototype.init = ContextType.HandleSymbolAsType;
 
-exports.emitEndStatement = function(context){
-    context.codeGenerator().write(";\n");
-};
-
-exports.While = ChainedContext.extend({
-    init: function WhileContext(context){
-        ChainedContext.prototype.init.call(this, context);
-        var gen = this.codeGenerator();
-        gen.write("while (true)");
-        gen.openScope();
-        gen.write("if (");
-    },
-    handleExpression: function WhileContext$handleExpression(e){
-        ContextIf.handleIfExpression(e);
-        var gen = this.codeGenerator();
-        gen.write(")");
-        gen.openScope();
-    },
-    handleLiteral: function(s){
-        if (s == "ELSIF"){
-            var gen = this.codeGenerator();
-            gen.closeScope("");
-            gen.write("else if (");
-        }
-    },
-    endParse: function(){
-        var gen = this.codeGenerator();
-        gen.closeScope(" else break;\n");
-        gen.closeScope("");
-    }
-});
-
-exports.Repeat = ChainedContext.extend({
-    init: function RepeatContext(context){
-        ChainedContext.prototype.init.call(this, context);
-        var gen = context.codeGenerator();
-        gen.write("do ");
-        gen.openScope();
-    }
-});
-
-exports.Until = ChainedContext.extend({
-    init: function UntilContext(context){
-        ChainedContext.prototype.init.call(this, context);
-        context.codeGenerator().closeScope(" while (");
-    },
-    codeGenerator: function(){ return nullCodeGenerator; },
-    handleExpression: function(e){
-        ContextIf.handleIfExpression(e);
-        this.parent().codeGenerator().write( op.not(e).code() );
-    },
-    endParse: function(){
-        this.parent().codeGenerator().write(");\n");
-    }
-});
-
-exports.For = ChainedContext.extend({
-    init: function ForContext(context){
-        ChainedContext.prototype.init.call(this, context);
-        this.__var = undefined;
-        this.__initExprParsed = false;
-        this.__toExpr = CodeGenerator.makeSimpleGenerator();
-        this.__toParsed = false;
-        this.__by_parsed = false;
-        this.__by = undefined;
-    },
-    handleIdent: function(id){
-        var s = ContextHierarchy.getSymbol(this.root(), id);
-        if (!s.isVariable())
-            throw new Errors.Error("'" + s.id() + "' is not a variable");
-        var type = s.info().type();
-        if (type !== basicTypes.integer)
-            throw new Errors.Error(
-                  "'" + s.id() + "' is a '" 
-		+ type.description() + "' variable, 'FOR' control variable must be 'INTEGER'");
-        this._handleInitCode(id, "for (" + id + " = ");
-    },
-    _handleInitCode: function(id, code){
-        this.__var = id;
-        this.codeGenerator().write(code);
-    },
-    _handleInitExpression: function(type){
-        if (type != basicTypes.integer)
-            throw new Errors.Error(
-                "'INTEGER' expression expected to assign '" + this.__var
-                + "', got '" + type.description() + "'");
-        this.__initExprParsed = true;
-    },
-    handleExpression: function(e){
-        var type = e.type();
-        if (!this.__initExprParsed)
-            this._handleInitExpression(type);
-        else if (!this.__toParsed) {
-            if (type != basicTypes.integer)
-                throw new Errors.Error(
-                    "'INTEGER' expression expected as 'TO' parameter, got '" + type.description() + "'");
-            this.__toParsed = true;
-        }
-        else {
-            if (type != basicTypes.integer)
-                throw new Errors.Error("'INTEGER' expression expected as 'BY' parameter, got '" + type.description() + "'");
-            var value = e.constValue();
-            if (!value)
-                throw new Errors.Error("constant expression expected as 'BY' parameter");
-            this.__by = value.value;
-        }
-    },
-    codeGenerator: function(){
-        if (this.__initExprParsed && !this.__toParsed)
-            return this.__toExpr;
-        if (this.__toParsed && !this.__by_parsed)
-            return nullCodeGenerator; // suppress output for BY expression
-        
-        return this.parent().codeGenerator();
-    },
-    handleBegin: function(){
-        this.__by_parsed = true;
-
-        var relation = this.__by < 0 ? " >= " : " <= ";
-        var step = this.__by === undefined
-                            ? "++" + this.__var
-                            : this.__var + (this.__by < 0
-                                    ? " -= " + -this.__by
-                                    : " += " +  this.__by);
-        var s = "; " + this.__var + relation + this.__toExpr.result() + "; " + step + ")";
-        var gen = this.codeGenerator();
-        gen.write(s);
-        gen.openScope();
-    },
-    endParse: function(){this.codeGenerator().closeScope("");}
-});
-
-exports.emitForBegin = function(context){context.handleBegin();};
-
 exports.CheckAssignment = ChainedContext.extend({
     init: function Context$CheckAssignment(context){
         ChainedContext.prototype.init.call(this, context);

+ 13 - 12
src/eberon/eberon_context.js

@@ -11,6 +11,7 @@ var ContextDesignator = require("js/ContextDesignator.js");
 var ContextExpression = require("js/ContextExpression.js");
 var ContextIdentdef = require("js/ContextIdentdef.js");
 var ContextIf = require("js/ContextIf.js");
+var ContextLoop = require("js/ContextLoop.js");
 var ContextHierarchy = require("js/ContextHierarchy.js");
 var ContextProcedure = require("js/ContextProcedure.js");
 var ContextType = require("js/ContextType.js");
@@ -1127,13 +1128,13 @@ var OperatorScopes = Class.extend({
     }
 });
 
-var While = Context.While.extend({
+var While = Class.extend.call(ContextLoop.While, {
     init: function EberonContext$While(context){
-        Context.While.prototype.init.call(this, context);
+        ContextLoop.While.call(this, context);
         this.__scopes = new OperatorScopes(this);
     },
     handleLiteral: function(s){
-        Context.While.prototype.handleLiteral.call(this, s);
+        ContextLoop.While.prototype.handleLiteral.call(this, s);
         if (s == "DO")
             this.__scopes.doThen();
         else if (s == "ELSIF")
@@ -1143,11 +1144,11 @@ var While = Context.While.extend({
         if (this.__scopes.handleMessage(msg))
             return;
 
-        return Context.While.prototype.handleMessage.call(this, msg);
+        return ContextLoop.While.prototype.handleMessage.call(this, msg);
     },
     endParse: function(){
         this.__scopes.reset();
-        Context.While.prototype.endParse.call(this);
+        ContextLoop.While.prototype.endParse.call(this);
     }
 });
 
@@ -1194,9 +1195,9 @@ var CaseLabel = Class.extend.call(ContextCase.Label, {
     }
 });
 
-var Repeat = Context.Repeat.extend({
+var Repeat = Class.extend.call(ContextLoop.Repeat, {
     init: function EberonContext$Repeat(context){
-        Context.Repeat.prototype.init.call(this, context);
+        ContextLoop.Repeat.call(this, context);
         var root = this.root();
         var scope = EberonScope.makeOperator(
             root.currentScope(),
@@ -1209,9 +1210,9 @@ var Repeat = Context.Repeat.extend({
     }
 });
 
-var For = Context.For.extend({
+var For = Class.extend.call(ContextLoop.For, {
     init: function EberonContext$Repeat(context){
-        Context.For.prototype.init.call(this, context);
+        ContextLoop.For.call(this, context);
         var root = this.root();
         var scope = EberonScope.makeOperator(
             root.currentScope(),
@@ -1219,12 +1220,12 @@ var For = Context.For.extend({
         root.pushScope(scope);
     },
     handleInPlaceInit: function(symbol, code){
-        this._handleInitCode(symbol.id(), "for (" + code);
-        this._handleInitExpression(symbol.info().type());
+        this.doHandleInitCode(symbol.id(), "for (" + code);
+        this.doHandleInitExpression(symbol.info().type());
     },
     endParse: function(){
         this.root().popScope();
-        Context.For.prototype.endParse.call(this);
+        ContextLoop.For.prototype.endParse.call(this);
     }
 });
 

+ 4 - 3
src/grammar.js

@@ -5,6 +5,7 @@ var ContextCase = require("js/ContextCase.js");
 var ContextDesignator = require("js/ContextDesignator.js");
 var ContextExpression = require("js/ContextExpression.js");
 var ContextIdentdef = require("js/ContextIdentdef.js");
+var ContextLoop = require("js/ContextLoop.js");
 var ContextProcedure = require("js/ContextProcedure.js");
 var ContextType = require("js/ContextType.js");
 var Lexer = require("js/Lexer.js");
@@ -139,18 +140,18 @@ var whileStatement = and("WHILE",
 var repeatStatement = and("REPEAT", 
                           context(and(statementSequence, 
                                       "UNTIL", 
-                                      context(expression, Context.Until)), 
+                                      context(expression, ContextLoop.Until)), 
                                   contexts.Repeat));
 
 var forStatement = and("FOR", 
                        context(and(makeForInit(ident, expression, assignment), "TO", expression
                                  , optional(and("BY", constExpression))
-                                 , emit("DO", Context.emitForBegin)
+                                 , emit("DO", ContextLoop.emitForBegin)
                                  , statementSequence, required("END", "END expected (FOR)"))
                              , contexts.For));
 
 var statement = optional(
-    makeStatement(or( emit(designator.assignmentOrProcedureCall(assignment, expression), Context.emitEndStatement),
+    makeStatement(or( emit(designator.assignmentOrProcedureCall(assignment, expression), ContextProcedure.emitEndStatement),
                       ifStatement,
                       caseStatement,
                       whileStatement,

+ 212 - 0
src/ob/ContextLoop.ob

@@ -0,0 +1,212 @@
+MODULE ContextLoop;
+IMPORT
+    Chars, CodeGenerator, ConstValue, Context, ContextExpression, ContextIf, ContextHierarchy, 
+    Errors, Expression, Operator, String, Types;
+TYPE
+    While* = RECORD(ContextExpression.ExpressionHandler)
+        PROCEDURE While(parent: ContextHierarchy.PNode);
+    END;
+
+    Repeat* = RECORD(ContextHierarchy.Node)
+        PROCEDURE Repeat(parent: ContextHierarchy.PNode);
+    END;
+
+    Until* = RECORD(ContextExpression.ExpressionHandler)
+        PROCEDURE Until(parent: ContextHierarchy.PNode);
+    END;
+
+    For* = RECORD(ContextExpression.ExpressionHandler)
+        PROCEDURE For(parent: ContextHierarchy.PNode);
+
+        PROCEDURE doHandleInitCode(id, code: STRING);
+        PROCEDURE doHandleInitExpression(type: Types.PType);
+
+        toExpr: CodeGenerator.PIGenerator;
+        var: STRING;
+        initExprParsed, toParsed, byParsed: BOOLEAN;
+        by: INTEGER;
+    END;
+
+PROCEDURE While.While(parent: ContextHierarchy.PNode)
+    | SUPER(parent);
+BEGIN
+    gen <- SELF.codeGenerator();
+    gen.write("while (true)");
+    gen.openScope();
+    gen.write("if (");
+END;
+
+PROCEDURE While.handleExpression(e: Expression.PType);
+BEGIN
+    ContextIf.handleIfExpression(e);
+    gen <- SELF.codeGenerator();
+    gen.write(")");
+    gen.openScope();
+END;
+
+PROCEDURE While.handleLiteral(s: STRING);
+BEGIN
+    IF s = "ELSIF" THEN
+        gen <- SELF.codeGenerator();
+        gen.closeScope("");
+        gen.write("else if (");
+    END;
+END;
+
+PROCEDURE While.endParse(): BOOLEAN;
+BEGIN
+    gen <- SELF.codeGenerator();
+    gen.closeScope(" else break;" + Chars.ln);
+    gen.closeScope("");
+    RETURN TRUE;
+END;
+
+PROCEDURE Repeat.Repeat(parent: ContextHierarchy.PNode)
+    | SUPER(parent);
+BEGIN
+    gen <- SELF.codeGenerator();
+    gen.write("do ");
+    gen.openScope();
+END;
+
+(*
+PROCEDURE Repeat.endParse(): BOOLEAN;
+BEGIN
+    SELF.root().popScope();
+    RETURN TRUE;
+END;
+*)
+
+PROCEDURE Until.Until(parent: ContextHierarchy.PNode)
+    | SUPER(parent);
+BEGIN
+    parent.codeGenerator().closeScope(" while (");
+END;
+
+PROCEDURE Until.codeGenerator(): CodeGenerator.PIGenerator;
+    RETURN CodeGenerator.nullGenerator;
+END;
+
+PROCEDURE Until.handleExpression(e: Expression.PType);
+BEGIN
+    ContextIf.handleIfExpression(e);
+    SELF.parent().codeGenerator().write( Operator.not(e).code() );
+END;
+
+PROCEDURE Until.endParse(): BOOLEAN;
+BEGIN
+    SELF.parent().codeGenerator().write(");" + Chars.ln);
+    RETURN TRUE;
+END;
+
+PROCEDURE For.For(parent: ContextHierarchy.PNode)
+    | SUPER(parent),
+      toExpr(CodeGenerator.makeSimpleGenerator()),
+      by(1);
+END;
+
+PROCEDURE For.handleIdent(id: STRING);
+BEGIN
+    s <- ContextHierarchy.getSymbol(SELF.root()^, id);
+    info <- s.info();
+    IF ~(info IS Types.PVariable) THEN
+        Errors.raise("'" + s.id() + "' is not a variable");
+    ELSE
+        type <- info.type();
+        IF type # Types.basic.integer THEN
+            Errors.raise("'" + s.id() + "' is a '" + type.description() 
+                         + "' variable, 'FOR' control variable must be 'INTEGER'");
+        END;
+        SELF.doHandleInitCode(id, "for (" + id + " = ");
+    END;
+END;
+
+PROCEDURE For.doHandleInitCode(id, code: STRING);
+BEGIN
+    SELF.var := id;
+    SELF.codeGenerator().write(code);
+END;
+
+PROCEDURE For.doHandleInitExpression(type: Types.PType);
+BEGIN
+    IF type # Types.basic.integer THEN
+        Errors.raise(
+            "'INTEGER' expression expected to assign '" + SELF.var
+            + "', got '" + type.description() + "'");
+    END;
+    SELF.initExprParsed := TRUE;
+END;
+
+PROCEDURE For.handleExpression(e: Expression.PType);
+BEGIN
+    type <- e.type();
+    IF ~SELF.initExprParsed THEN
+        SELF.doHandleInitExpression(type);
+    ELSIF ~SELF.toParsed THEN
+        IF type # Types.basic.integer THEN
+            Errors.raise("'INTEGER' expression expected as 'TO' parameter, got '" 
+                         + type.description() + "'");
+        END;
+        SELF.toParsed := TRUE;
+    ELSE
+        IF type # Types.basic.integer THEN
+            Errors.raise("'INTEGER' expression expected as 'BY' parameter, got '" 
+                         + type.description() + "'");
+        END;
+        value <- e.constValue();
+        IF value = NIL THEN
+            Errors.raise("constant expression expected as 'BY' parameter");
+        END;
+        SELF.by := value(ConstValue.PInt).value;
+    END;
+END;
+
+PROCEDURE For.codeGenerator(): CodeGenerator.PIGenerator;
+VAR
+    result: CodeGenerator.PIGenerator;
+BEGIN
+    IF SELF.initExprParsed & ~SELF.toParsed THEN
+        result := SELF.toExpr;
+    ELSIF SELF.toParsed & ~SELF.byParsed THEN
+        result := CodeGenerator.nullGenerator; (* suppress output for BY expression *)
+    ELSE    
+        result := SELF.parent().codeGenerator();
+    END;
+    RETURN result;
+END;
+
+PROCEDURE For.endParse(): BOOLEAN;
+BEGIN
+    SELF.codeGenerator().closeScope("");
+    RETURN TRUE;
+END;
+
+PROCEDURE emitForBegin*(VAR cx: For);
+VAR
+    relation, step: STRING;
+BEGIN
+    cx.byParsed := TRUE;
+
+    IF cx.by < 0 THEN
+        relation := " >= ";
+    ELSE
+        relation := " <= ";
+    END;
+
+    IF cx.by = 1 THEN
+        step := "++" + cx.var;
+    ELSIF cx.by = -1 THEN
+        step := "--" + cx.var;
+    ELSIF cx.by < 0 THEN
+        step := cx.var + " -= " + String.fromInt(-cx.by);
+    ELSE
+        step := cx.var + " += " + String.fromInt(cx.by);
+    END;
+
+    s <- "; " + cx.var + relation + cx.toExpr.result() + "; " + step + ")";
+    gen <- cx.codeGenerator();
+    gen.write(s);
+    gen.openScope();
+END;
+
+END ContextLoop.

+ 5 - 0
src/ob/ContextProcedure.ob

@@ -275,4 +275,9 @@ PROCEDURE AddArgumentMsg.AddArgumentMsg(name: STRING; arg: Types.PProcedureArgum
       arg(arg);
 END;
 
+PROCEDURE emitEndStatement*(cx: ContextHierarchy.Node);
+BEGIN
+    cx.codeGenerator().write(";" + Chars.ln);
+END;
+
 END ContextProcedure.

+ 4 - 3
src/oberon/oberon_grammar.js

@@ -9,6 +9,7 @@ var ContextDesignator = require("js/ContextDesignator.js");
 var ContextExpression = require("js/ContextExpression.js");
 var ContextIdentdef = require("js/ContextIdentdef.js");
 var ContextIf = require("js/ContextIf.js");
+var ContextLoop = require("js/ContextLoop.js");
 var ContextProcedure = require("js/ContextProcedure.js");
 var ContextType = require("js/ContextType.js");
 var Grammar = require("grammar.js");
@@ -126,11 +127,11 @@ exports.language = {
             MulOperator:        ContextExpression.MulOperator,
             SimpleExpression:   ContextExpression.SimpleExpression, 
             Expression:         ContextExpression.ExpressionNode,
-            For:                Context.For,
-            While:              Context.While,
+            For:                ContextLoop.For,
+            While:              ContextLoop.While,
             If:                 ContextIf.Type,
             CaseLabel:          ContextCase.Label,
-            Repeat:             Context.Repeat,
+            Repeat:             ContextLoop.Repeat,
             ModuleDeclaration:  Context.ModuleDeclaration
         },
         Grammar.reservedWords

+ 1 - 1
test/expected/for.js

@@ -9,7 +9,7 @@ for (i = 0; i <= 10; i += 5){
 	b1 = true;
 }
 for (i = 15; i >= 0; i -= 3){
-	for (i1 = 1; i1 >= 3; i1 -= 1){
+	for (i1 = 1; i1 >= 3; --i1){
 		b1 = true;
 	}
 	i1 = -2;

+ 7 - 4
test/test_unit.js

@@ -683,12 +683,15 @@ return {
     ),
 "FOR statement": testWithContext(
     context(grammar.statement,
-              "CONST c = 15;"
+              "CONST c = 15; zero = 1 - 1;"
             + "VAR b: BOOLEAN; i, n: INTEGER; ch: CHAR; p: POINTER TO RECORD END;"),
     pass("FOR i := 0 TO 10 DO n := 1 END",
          "FOR i := 0 TO 10 BY 5 DO b := TRUE END",
          "FOR i := 0 TO n DO b := TRUE END",
-         "FOR i := 0 TO n BY c DO n := 1; b := FALSE END"),
+         "FOR i := 0 TO n BY c DO n := 1; b := FALSE END",
+         "FOR i := 0 TO 10 BY 0 DO b := TRUE END",
+         "FOR i := 0 TO 10 BY zero DO b := TRUE END"
+         ),
     fail(["FOR undefined := 0 TO 10 DO n := 1 END",
           "undeclared identifier: 'undefined'"],
          ["FOR b := TRUE TO 10 DO n := 1 END",
@@ -710,8 +713,8 @@ return {
           "'INTEGER' expression expected as 'BY' parameter, got 'POINTER TO anonymous RECORD'"],
          ["FOR i := 0 TO 10 BY TRUE DO END",
           "'INTEGER' expression expected as 'BY' parameter, got 'BOOLEAN'"],
-         ["FOR i := 0 TO 10 DO - END",
-          "END expected (FOR)"])
+         ["FOR i := 0 TO 10 DO - END", "END expected (FOR)"]
+         )
     ),
 "logical operators": testWithContext(
     context(grammar.statement, "VAR b1, b2: BOOLEAN; i1: INTEGER; p: POINTER TO RECORD END;"),