Browse Source

code generation for methods

Vladislav Folts 11 năm trước cách đây
mục cha
commit
385c690de5

+ 2 - 1
src/context.js

@@ -523,7 +523,7 @@ exports.ProcDecl = ChainedContext.extend({
     },
     },
     handleIdentdef: function(id){
     handleIdentdef: function(id){
         this.__id = id;
         this.__id = id;
-        this.codeGenerator().write("\nfunction " + id.id() + "(");
+        this.codeGenerator().write(this._prolog());
         this.parent().pushScope(new Scope.Procedure());
         this.parent().pushScope(new Scope.Procedure());
     },
     },
     handleIdent: function(id){
     handleIdent: function(id){
@@ -533,6 +533,7 @@ exports.ProcDecl = ChainedContext.extend({
         this.codeGenerator().closeScope();
         this.codeGenerator().closeScope();
         this.parent().popScope();
         this.parent().popScope();
     },
     },
+    _prolog: function(){return "\nfunction " + this.__id.id() + "(";},
     typeName: function(){return undefined;},
     typeName: function(){return undefined;},
     setType: function(type){
     setType: function(type){
         var procSymbol = new Symbol.Symbol(this.__id.id(), type);
         var procSymbol = new Symbol.Symbol(this.__id.id(), type);

+ 12 - 1
src/eberon/eberon_context.js

@@ -60,14 +60,20 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
         this.__selfSymbol = undefined;
         this.__selfSymbol = undefined;
         this.__methodId = undefined;
         this.__methodId = undefined;
         this.__methodType = undefined;
         this.__methodType = undefined;
+        this.__boundType = undefined;
         this.__isNew = undefined;
         this.__isNew = undefined;
         this.__endingId = undefined;
         this.__endingId = undefined;
     },
     },
-    handleMessage: function(msg){return this.__selfSymbol;},
+    handleMessage: function(msg){
+        if (msg == getMethodSelf)
+            return this.__selfSymbol;
+        return Context.ProcDecl.prototype.handleMessage.call(this, msg);
+    },
     handleMethodOrProc: function(id, type){
     handleMethodOrProc: function(id, type){
         if (type){
         if (type){
             this.__selfSymbol = new Symbol.Symbol("SELF", type);
             this.__selfSymbol = new Symbol.Symbol("SELF", type);
             this.__methodId = id;
             this.__methodId = id;
+            this.__boundType = type;
         }
         }
 
 
         Context.ProcDecl.prototype.handleIdentdef.call(
         Context.ProcDecl.prototype.handleIdentdef.call(
@@ -77,6 +83,11 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
                  : id
                  : id
             );
             );
     },
     },
+    _prolog: function(){
+        return this.__boundType
+            ? this.__boundType.name() + ".prototype." + this.__methodId.id() + " = function("
+            : Context.ProcDecl.prototype._prolog.call(this);
+    },
     setType: function(type){
     setType: function(type){
         Context.ProcDecl.prototype.setType.call(this, type);
         Context.ProcDecl.prototype.setType.call(this, type);
         this.__methodType = new MethodType(type);
         this.__methodType = new MethodType(type);

+ 24 - 0
test/expected/eberon/method.js

@@ -0,0 +1,24 @@
+var RTL$ = {
+    extend: function extend(methods){
+        function Type(){
+            for(var m in methods)
+                this[m] = methods[m];
+        }
+        Type.prototype = this.prototype;
+
+        var result = methods.init;
+        result.prototype = new Type(); // inherit this.prototype
+        result.prototype.constructor = result; // to see constructor name in diagnostic
+        
+        result.extend = extend;
+        return result;
+    }
+};
+var m = function (){
+var T = RTL$.extend({
+	init: function T(){
+	}
+});
+T.prototype.p = function(){
+}
+}();

+ 8 - 0
test/input/eberon/method.ob

@@ -0,0 +1,8 @@
+MODULE m;
+TYPE
+    T = RECORD END;
+
+PROCEDURE T.p(), NEW;
+END T.p;
+
+END m.

+ 33 - 0
test/input/eberon/run/method.ob

@@ -0,0 +1,33 @@
+MODULE m;
+TYPE
+    T = RECORD END;
+	TD = RECORD(T) END;
+
+VAR
+    pCalled: BOOLEAN;
+    pDerivedCalled: BOOLEAN;
+	r: T;
+	rd: TD;
+
+PROCEDURE T.p(), NEW;
+BEGIN
+	pCalled := TRUE;
+END T.p;
+
+PROCEDURE TD.p();
+BEGIN
+	pDerivedCalled := TRUE;
+END TD.p;
+
+BEGIN
+	ASSERT(~pCalled);
+	ASSERT(~pDerivedCalled);
+	r.p();
+	ASSERT(pCalled);
+	ASSERT(~pDerivedCalled);
+
+	pCalled := FALSE;
+	rd.p();
+	ASSERT(~pCalled);
+	ASSERT(pDerivedCalled);
+END m.

+ 59 - 43
test/test_compile.js

@@ -3,6 +3,7 @@
 var nodejs = require("nodejs");
 var nodejs = require("nodejs");
 var oc = require("oc");
 var oc = require("oc");
 var oberonGrammar = require("oberon/oberon_grammar.js").grammar;
 var oberonGrammar = require("oberon/oberon_grammar.js").grammar;
+var eberonGrammar = require("eberon/eberon_grammar.js").grammar;
 var fs = require("fs");
 var fs = require("fs");
 var path = require("path");
 var path = require("path");
 var Test = require("test.js");
 var Test = require("test.js");
@@ -19,16 +20,16 @@ function compareResults(result, name, dirs){
         throw new Test.TestError("Failed");
         throw new Test.TestError("Failed");
 }
 }
 
 
-function compile(src){
+function compile(src, grammar){
     var text = fs.readFileSync(src, "utf8");
     var text = fs.readFileSync(src, "utf8");
     var errors = "";
     var errors = "";
-    var result = oc.compile(text, oberonGrammar, function(e){errors += e;});
+    var result = oc.compile(text, grammar, function(e){errors += e;});
     if (errors)
     if (errors)
         throw new Test.TestError(errors);
         throw new Test.TestError(errors);
     return result;
     return result;
 }
 }
 
 
-function compileNodejs(src, dirs){
+function compileNodejs(src, dirs, grammar){
     var subdir = path.basename(src);
     var subdir = path.basename(src);
     subdir = subdir.substr(0, subdir.length - path.extname(subdir).length);
     subdir = subdir.substr(0, subdir.length - path.extname(subdir).length);
 
 
@@ -36,24 +37,24 @@ function compileNodejs(src, dirs){
     fs.mkdirSync(outDir);
     fs.mkdirSync(outDir);
 
 
     var errors = "";
     var errors = "";
-    nodejs.compile([src], oberonGrammar, function(e){errors += e;}, outDir);
+    nodejs.compile([src], grammar, function(e){errors += e;}, outDir);
     if (errors)
     if (errors)
         throw new Test.TestError(errors);
         throw new Test.TestError(errors);
 
 
     cmpDirs(path.join(dirs.expected, subdir), outDir);
     cmpDirs(path.join(dirs.expected, subdir), outDir);
 }
 }
 
 
-function expectOk(src, dirs){
-    var result = compile(src);
+function expectOk(src, dirs, grammar){
+    var result = compile(src, grammar);
     var resultName = path.basename(src).replace(".ob", ".js");
     var resultName = path.basename(src).replace(".ob", ".js");
     compareResults(result, resultName, dirs);
     compareResults(result, resultName, dirs);
 }
 }
 
 
-function expectError(src, dirs){
+function expectError(src, dirs, grammar){
     var text = fs.readFileSync(src, "utf8");
     var text = fs.readFileSync(src, "utf8");
     var errors = "";
     var errors = "";
     try {
     try {
-        oc.compile(text, oberonGrammar, function(e){errors += e + "\n";});
+        oc.compile(text, grammar, function(e){errors += e + "\n";});
     }
     }
     catch (e){
     catch (e){
         errors += e;
         errors += e;
@@ -64,26 +65,31 @@ function expectError(src, dirs){
     compareResults(errors, resultName, dirs);
     compareResults(errors, resultName, dirs);
 }
 }
 
 
-function run(src, dirs){
-    var result = compile(src);
+function run(src, dirs, grammar){
+    var result = compile(src, grammar);
     var resultName = path.basename(src).replace(".ob", ".js");
     var resultName = path.basename(src).replace(".ob", ".js");
     var resultPath = path.join(dirs.output, resultName);
     var resultPath = path.join(dirs.output, resultName);
     fs.writeFileSync(resultPath, result);
     fs.writeFileSync(resultPath, result);
     require(resultPath);
     require(resultPath);
 }
 }
 
 
-function makeTest(test, src, dirs){
-    return function(){test(src, dirs);};
+function makeTest(test, src, dirs, grammar){
+    return function(){test(src, dirs, grammar);};
 }
 }
 
 
-function makeTests(test, dirs){
+function makeTests(test, dirs, grammar){
+    var output = dirs.output;
+    if (fs.existsSync(output))
+        rmTree(output);
+    fs.mkdirSync(output);
+
     var sources = fs.readdirSync(dirs.input);
     var sources = fs.readdirSync(dirs.input);
     var tests = {};
     var tests = {};
     for(var i = 0; i < sources.length; ++i){
     for(var i = 0; i < sources.length; ++i){
         var source = sources[i];
         var source = sources[i];
         var filePath = path.join(dirs.input, source);
         var filePath = path.join(dirs.input, source);
         if (fs.statSync(filePath).isFile())
         if (fs.statSync(filePath).isFile())
-            tests[source] = makeTest(test, filePath, dirs);
+            tests[source] = makeTest(test, filePath, dirs, grammar);
     }
     }
     return tests;
     return tests;
 }
 }
@@ -113,39 +119,49 @@ function cmpDirs(expected, result){
     });
     });
 }
 }
 
 
-function main(){
-    if (process.argv.length > 2){
-        var tests = {};
-        var name = process.argv[2];
-        tests[name] = function(){run(name);};
-        Test.run(tests);
-        return;
-    }
+var testDirs = {input: "input", output: "output", expected: "expected"};
 
 
-    var okDirs = {input: "input", output: "output", expected: "expected"};
-    var errDirs = {};
-    var runDirs = {};
-    var nodejsDirs = {};
-    var p;
-    for(p in okDirs){
-        errDirs[p] = path.join(okDirs[p], "errors");
-        runDirs[p] = path.join(okDirs[p], "run");
-        nodejsDirs[p] = path.join(okDirs[p], "nodejs");
-    }
+function makeTestDirs(subdir){
+    if (!subdir)
+        return testDirs;
 
 
-    var dirsSet = [okDirs, errDirs, runDirs, nodejsDirs];
-    for(var i = 0; i < dirsSet.length; ++i){
-        var output = dirsSet[i].output;
-        if (fs.existsSync(output))
-            rmTree(output);
-        fs.mkdirSync(output);
+    var result = {};
+    for(var p in testDirs)
+        result[p] = path.join(testDirs[p], subdir);
+    return result;
+}
+
+function outputSubdir(dirs, subdir){
+    var result = {};
+    for(var p in dirs)
+        result[p] = (p == "output") ? path.join(dirs[p], subdir) : dirs[p];
+    return result;
+}
+
+function main(){
+    var okDirs = makeTestDirs();
+    var errDirs = makeTestDirs("errors");
+    var runDirs = makeTestDirs("run");
+    var nodejsDirs = makeTestDirs("nodejs");
+    var eberonDirs = makeTestDirs("eberon");
+    var eberonRunDirs = makeTestDirs("eberon/run");
+
+    function makeCommonTests(grammar, subdir){
+        return {
+            "expect OK": makeTests(expectOk, outputSubdir(okDirs, subdir), grammar),
+            "expect compile error": makeTests(expectError, outputSubdir(errDirs, subdir), grammar),
+            "run": makeTests(run, outputSubdir(runDirs, subdir), grammar),
+            "nodejs": makeTests(compileNodejs, outputSubdir(nodejsDirs, subdir), grammar)
+        };
     }
     }
 
 
-    Test.run({"expect OK": makeTests(expectOk, okDirs, compile),
-              "expect compile error": makeTests(expectError, errDirs),
-              "run": makeTests(run, runDirs),
-              "nodejs": makeTests(compileNodejs, nodejsDirs)}
-            );
+    Test.run({"common": {"oberon": makeCommonTests(oberonGrammar, "oberon"),
+                         "eberon": makeCommonTests(eberonGrammar, "eberon")
+                        },
+              "eberon": {"expect OK": makeTests(expectOk, eberonDirs, eberonGrammar),
+                         "run": makeTests(run, eberonRunDirs, eberonGrammar)
+                        }
+             });
 }
 }
 
 
 main();
 main();