diff --git a/build/scscript.js b/build/scscript.js index 0dd4b1c..338feca 100644 --- a/build/scscript.js +++ b/build/scscript.js @@ -1,7 +1,7 @@ (function(global) { "use strict"; -var sc = { VERSION: "0.0.20" }; +var sc = { VERSION: "0.0.21" }; // src/sc/sc.js (function(sc) { @@ -11,7 +11,7 @@ var sc = { VERSION: "0.0.20" }; sc.libs = {}; function SCScript(fn) { - return fn(sc.lang.$SC); + return fn(sc.lang.klass.$interpreter, sc.lang.$SC); } SCScript.install = function(installer) { @@ -260,6 +260,17 @@ var sc = { VERSION: "0.0.20" }; } stream.push(stmt.head, stmt.vars, stmt.tail); + }, + begin_ref: function() { + var refId = (this._refId | 0); + var refName = "_ref" + refId; + this.add("var", refName); + this._refId = refId + 1; + return refName; + }, + end_ref: function() { + var refId = (this._refId | 0) - 1; + this._refId = Math.max(0, refId); } }); @@ -453,8 +464,10 @@ var sc = { VERSION: "0.0.20" }; var elements = node.left; var operator = node.operator; var assignments; + var result; + var ref; - this.scope.add("var", "_ref"); + ref = this.scope.begin_ref(); assignments = this.withIndent(function() { var result, lastUsedIndex; @@ -464,25 +477,29 @@ var sc = { VERSION: "0.0.20" }; result = [ this.stitchWith(elements, ",\n", function(item, i) { return this.addIndent(this._Assign( - item, operator, "_ref.at($SC.Integer(" + i + "))" + item, operator, ref + ".at($SC.Integer(" + i + "))" )); }) ]; if (node.remain) { result.push(",\n", this.addIndent(this._Assign( - node.remain, operator, "_ref.copyToEnd($SC.Integer(" + lastUsedIndex + "))" + node.remain, operator, ref + ".copyToEnd($SC.Integer(" + lastUsedIndex + "))" ))); } return result; }); - return [ - "(_ref = ", this.generate(node.right), ",\n", + result = [ + "(" + ref + " = ", this.generate(node.right), ",\n", assignments , ",\n", - this.addIndent("_ref)") + this.addIndent(ref + ")") ]; + + this.scope.end_ref(); + + return result; }; CodeGen.prototype._Assign = function(left, operator, right) { @@ -565,37 +582,53 @@ var sc = { VERSION: "0.0.20" }; var args; var list; var hasActualArgument; + var result; + var ref; list = node.args.list; hasActualArgument = !!list.length; - args = [ - this.stitchWith(list, ", ", function(item) { - return this.generate(item); - }), - this.insertKeyValueElement(node.args.keywords, hasActualArgument) - ]; + if (node.stamp === "=") { + ref = this.scope.begin_ref(); + result = [ + "(" + ref + " = ", this.generate(list[0]), ", ", + this.generate(node.callee), ".", node.method.name, "(" + ref + "), ", + ref + ")" + ]; + this.scope.end_ref(); + } else { + args = [ + this.stitchWith(list, ", ", function(item) { + return this.generate(item); + }), + this.insertKeyValueElement(node.args.keywords, hasActualArgument) + ]; + result = [ + this.generate(node.callee), ".", node.method.name, "(", args, ")" + ]; + } - return [ - this.generate(node.callee), ".", node.method.name, "(", args, ")" - ]; + return result; }; CodeGen.prototype._ExpandCall = function(node) { var result; + var ref; - this.scope.add("var", "_ref"); + ref = this.scope.begin_ref(); result = [ - "(_ref = ", + "(" + ref + " = ", this.generate(node.callee), - ", _ref." + node.method.name + ".apply(_ref, ", + ", " + ref + "." + node.method.name + ".apply(" + ref + ", ", this.insertArrayElement(node.args.list), ".concat(", this.generate(node.args.expand), ".asArray()._", this.insertKeyValueElement(node.args.keywords, true), ")))" ]; + this.scope.end_ref(); + return result; }; @@ -800,14 +833,17 @@ var sc = { VERSION: "0.0.20" }; }; CodeGen.prototype._InterpreterVariable = function(node, opts) { - var name; + var name, ref; if (opts) { // setter + ref = this.scope.begin_ref(); name = [ - "$this." + node.name + "_(", this.generate(opts.right), ")" + "(" + ref + " = ", this.generate(opts.right), + ", $this." + node.name + "_(" + ref + "), " + ref + ")" ]; opts.used = true; + this.scope.end_ref(); } else { // getter name = "$this." + node.name + "()"; @@ -2272,7 +2308,7 @@ var sc = { VERSION: "0.0.20" }; }; SCParser.prototype.parseSimpleAssignmentExpression = function() { - var node, left, right, token, marker; + var node, left, right, token, methodName, marker; node = left = this.parsePartialExpression(); @@ -2282,9 +2318,12 @@ var sc = { VERSION: "0.0.20" }; token = this.lex(); right = this.parseAssignmentExpression(); - left.method.name = renameGetterToSetter(left.method.name); + methodName = renameGetterToSetter(left.method.name); + left.method.name = methodName; left.args.list = node.args.list.concat(right); - + if (methodName.charAt(methodName.length - 1) === "_") { + left.stamp = "="; + } node = marker.update().apply(left, true); } else { if (!isLeftHandSide(left)) { @@ -4487,6 +4526,11 @@ var sc = { VERSION: "0.0.20" }; __tag: 12 }); + function SCInterpreter() { + this.__initializeWith__("Object"); + } + klass.define(SCInterpreter, "Interpreter"); + // $SC var $nil = new SCNil(); var $true = new SCTrue(); @@ -4588,6 +4632,8 @@ var sc = { VERSION: "0.0.20" }; return instance; }; + sc.lang.klass.$interpreter = new SCInterpreter(); + })(sc); // src/sc/lang/klass/utils.js @@ -8463,6 +8509,8 @@ var sc = { VERSION: "0.0.20" }; // src/sc/lang/classlib/Core/Kernel.js (function(sc) { + var fn = sc.lang.fn; + sc.lang.klass.refine("Class", { // TODO: implements superclass // TODO: implements asClass @@ -8495,6 +8543,45 @@ var sc = { VERSION: "0.0.20" }; // TODO: implements superclasses }); + sc.lang.klass.refine("Interpreter", function(spec, utils) { + var $nil = utils.$nil; + + (function() { + var i, ch; + + function getter(name) { + return function() { + return this["_" + name] || $nil; + }; + } + + function setter(name) { + return fn(function(value) { + this["_" + name] = value; + return this; + }, "value"); + } + + for (i = 97; i <= 122; i++) { + ch = String.fromCharCode(i); + spec[ch] = getter(ch); + spec[ch + "_"] = setter(ch); + } + })(); + + spec.$new = function() { + throw new Error("Interpreter.new is illegal."); + }; + + spec.clearAll = function() { + var i; + for (i = 97; i <= 122; i++) { + this["_" + String.fromCharCode(i)] = $nil; + } + return this; + }; + }); + })(sc); // src/sc/lang/classlib/Core/Function.js diff --git a/package.json b/package.json index 3b8b3e5..577f4ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scscript", - "version": "0.0.20", + "version": "0.0.21", "author": "Nao Yonamine ", "homepage": "http://mohayonao.github.io/SCScript/", "bugs": "https://github.com/mohayonao/SCScript/issues", diff --git a/src/sc/lang/compiler/codegen.js b/src/sc/lang/compiler/codegen.js index d7cf6f4..2a653f0 100644 --- a/src/sc/lang/compiler/codegen.js +++ b/src/sc/lang/compiler/codegen.js @@ -60,6 +60,17 @@ } stream.push(stmt.head, stmt.vars, stmt.tail); + }, + begin_ref: function() { + var refId = (this._refId | 0); + var refName = "_ref" + refId; + this.add("var", refName); + this._refId = refId + 1; + return refName; + }, + end_ref: function() { + var refId = (this._refId | 0) - 1; + this._refId = Math.max(0, refId); } }); @@ -254,8 +265,10 @@ var elements = node.left; var operator = node.operator; var assignments; + var result; + var ref; - this.scope.add("var", "_ref"); + ref = this.scope.begin_ref(); assignments = this.withIndent(function() { var result, lastUsedIndex; @@ -265,25 +278,29 @@ result = [ this.stitchWith(elements, ",\n", function(item, i) { return this.addIndent(this._Assign( - item, operator, "_ref.at($SC.Integer(" + i + "))" + item, operator, ref + ".at($SC.Integer(" + i + "))" )); }) ]; if (node.remain) { result.push(",\n", this.addIndent(this._Assign( - node.remain, operator, "_ref.copyToEnd($SC.Integer(" + lastUsedIndex + "))" + node.remain, operator, ref + ".copyToEnd($SC.Integer(" + lastUsedIndex + "))" ))); } return result; }); - return [ - "(_ref = ", this.generate(node.right), ",\n", + result = [ + "(" + ref + " = ", this.generate(node.right), ",\n", assignments , ",\n", - this.addIndent("_ref)") + this.addIndent(ref + ")") ]; + + this.scope.end_ref(); + + return result; }; CodeGen.prototype._Assign = function(left, operator, right) { @@ -366,37 +383,53 @@ var args; var list; var hasActualArgument; + var result; + var ref; list = node.args.list; hasActualArgument = !!list.length; - args = [ - this.stitchWith(list, ", ", function(item) { - return this.generate(item); - }), - this.insertKeyValueElement(node.args.keywords, hasActualArgument) - ]; + if (node.stamp === "=") { + ref = this.scope.begin_ref(); + result = [ + "(" + ref + " = ", this.generate(list[0]), ", ", + this.generate(node.callee), ".", node.method.name, "(" + ref + "), ", + ref + ")" + ]; + this.scope.end_ref(); + } else { + args = [ + this.stitchWith(list, ", ", function(item) { + return this.generate(item); + }), + this.insertKeyValueElement(node.args.keywords, hasActualArgument) + ]; + result = [ + this.generate(node.callee), ".", node.method.name, "(", args, ")" + ]; + } - return [ - this.generate(node.callee), ".", node.method.name, "(", args, ")" - ]; + return result; }; CodeGen.prototype._ExpandCall = function(node) { var result; + var ref; - this.scope.add("var", "_ref"); + ref = this.scope.begin_ref(); result = [ - "(_ref = ", + "(" + ref + " = ", this.generate(node.callee), - ", _ref." + node.method.name + ".apply(_ref, ", + ", " + ref + "." + node.method.name + ".apply(" + ref + ", ", this.insertArrayElement(node.args.list), ".concat(", this.generate(node.args.expand), ".asArray()._", this.insertKeyValueElement(node.args.keywords, true), ")))" ]; + this.scope.end_ref(); + return result; }; @@ -601,14 +634,17 @@ }; CodeGen.prototype._InterpreterVariable = function(node, opts) { - var name; + var name, ref; if (opts) { // setter + ref = this.scope.begin_ref(); name = [ - "$this." + node.name + "_(", this.generate(opts.right), ")" + "(" + ref + " = ", this.generate(opts.right), + ", $this." + node.name + "_(" + ref + "), " + ref + ")" ]; opts.used = true; + this.scope.end_ref(); } else { // getter name = "$this." + node.name + "()"; diff --git a/src/sc/lang/compiler/parser.js b/src/sc/lang/compiler/parser.js index a7a615f..304ca79 100644 --- a/src/sc/lang/compiler/parser.js +++ b/src/sc/lang/compiler/parser.js @@ -390,7 +390,7 @@ }; SCParser.prototype.parseSimpleAssignmentExpression = function() { - var node, left, right, token, marker; + var node, left, right, token, methodName, marker; node = left = this.parsePartialExpression(); @@ -400,9 +400,12 @@ token = this.lex(); right = this.parseAssignmentExpression(); - left.method.name = renameGetterToSetter(left.method.name); + methodName = renameGetterToSetter(left.method.name); + left.method.name = methodName; left.args.list = node.args.list.concat(right); - + if (methodName.charAt(methodName.length - 1) === "_") { + left.stamp = "="; + } node = marker.update().apply(left, true); } else { if (!isLeftHandSide(left)) { diff --git a/src/sc/lang/compiler/test-cases.js b/src/sc/lang/compiler/test-cases.js index 5dc9ad6..75b0fb2 100644 --- a/src/sc/lang/compiler/test-cases.js +++ b/src/sc/lang/compiler/test-cases.js @@ -573,7 +573,8 @@ "a = 2pi": { compiled: [ "SCScript(function($this, $SC) {", - " return $this.a_($SC.Float(6.283185307179586));", + " var _ref0;", + " return (_ref0 = $SC.Float(6.283185307179586), $this.a_(_ref0), _ref0);", "});", ], ast: { @@ -618,11 +619,11 @@ "#a, b = c": { compiled: [ "SCScript(function($this, $SC) {", - " var _ref;", - " return (_ref = $this.c(),", - " $this.a_(_ref.at($SC.Integer(0))),", - " $this.b_(_ref.at($SC.Integer(1))),", - " _ref);", + " var _ref0, _ref1;", + " return (_ref0 = $this.c(),", + " (_ref1 = _ref0.at($SC.Integer(0)), $this.a_(_ref1), _ref1),", + " (_ref1 = _ref0.at($SC.Integer(1)), $this.b_(_ref1), _ref1),", + " _ref0);", "});", ], ast: { @@ -677,12 +678,12 @@ "#a, b ... c = d": { compiled: [ "SCScript(function($this, $SC) {", - " var _ref;", - " return (_ref = $this.d(),", - " $this.a_(_ref.at($SC.Integer(0))),", - " $this.b_(_ref.at($SC.Integer(1))),", - " $this.c_(_ref.copyToEnd($SC.Integer(2))),", - " _ref);", + " var _ref0, _ref1;", + " return (_ref0 = $this.d(),", + " (_ref1 = _ref0.at($SC.Integer(0)), $this.a_(_ref1), _ref1),", + " (_ref1 = _ref0.at($SC.Integer(1)), $this.b_(_ref1), _ref1),", + " (_ref1 = _ref0.copyToEnd($SC.Integer(2)), $this.c_(_ref1), _ref1),", + " _ref0);", "});", ], ast: { @@ -746,17 +747,17 @@ "#a, b = #c, d = [ 0, 1 ]": { compiled: [ "SCScript(function($this, $SC) {", - " var _ref;", - " return (_ref = (_ref = $SC.Array([", + " var _ref0, _ref1, _ref2;", + " return (_ref0 = (_ref1 = $SC.Array([", " $SC.Integer(0),", " $SC.Integer(1),", " ]),", - " $this.c_(_ref.at($SC.Integer(0))),", - " $this.d_(_ref.at($SC.Integer(1))),", - " _ref),", - " $this.a_(_ref.at($SC.Integer(0))),", - " $this.b_(_ref.at($SC.Integer(1))),", - " _ref);", + " (_ref2 = _ref1.at($SC.Integer(0)), $this.c_(_ref2), _ref2),", + " (_ref2 = _ref1.at($SC.Integer(1)), $this.d_(_ref2), _ref2),", + " _ref1),", + " (_ref1 = _ref0.at($SC.Integer(0)), $this.a_(_ref1), _ref1),", + " (_ref1 = _ref0.at($SC.Integer(1)), $this.b_(_ref1), _ref1),", + " _ref0);", "});", ], ast: { @@ -908,7 +909,8 @@ "a.b.c = 1": { compiled: [ "SCScript(function($this, $SC) {", - " return $this.a().b().c_($SC.Integer(1));", + " var _ref0;", + " return (_ref0 = $SC.Integer(1), $this.a().b().c_(_ref0), _ref0);", "});", ], ast: { @@ -945,6 +947,7 @@ end : { line: 1, column: 3 } } }, + stamp: "=", method: { type: Syntax.Identifier, name: "c_", @@ -2075,10 +2078,11 @@ "a[b[c=0;1]=0;1]": { compiled: [ "SCScript(function($this, $SC) {", + " var _ref0;", " return $this.a().at(" + - "($this.b().put(" + - "($this.c_($SC.Integer(0)), $SC.Integer(1)), $SC.Integer(0)" + - "), $SC.Integer(1))" + + "($this.b().put((" + + "(_ref0 = $SC.Integer(0), $this.c_(_ref0), _ref0), " + + "$SC.Integer(1)), $SC.Integer(0)), $SC.Integer(1))" + ");", "});", ], @@ -3491,9 +3495,10 @@ "a = #{}": { compiled: [ "SCScript(function($this, $SC) {", - " return $this.a_($SC.Function(function() {", + " var _ref0;", + " return (_ref0 = $SC.Function(function() {", " return $SC.Nil();", - " }, '', true));", + " }, '', true), $this.a_(_ref0), _ref0);", "});", ], ast: { @@ -3956,10 +3961,10 @@ "var a; #a = [];": { compiled: [ "SCScript(function($this, $SC) {", - " var $a = $SC.Nil(), _ref;", - " return (_ref = $SC.Array([]),", - " $a = _ref.at($SC.Integer(0)),", - " _ref);", + " var $a = $SC.Nil(), _ref0;", + " return (_ref0 = $SC.Array([]),", + " $a = _ref0.at($SC.Integer(0)),", + " _ref0);", "});", ], ast: { @@ -4423,8 +4428,8 @@ "max(0, 1, 2, *a, a: 5, b: 6)": { compiled: [ "SCScript(function($this, $SC) {", - " var _ref;", - " return (_ref = $SC.Integer(0), _ref.max.apply(_ref, [", + " var _ref0;", + " return (_ref0 = $SC.Integer(0), _ref0.max.apply(_ref0, [", " $SC.Integer(1),", " $SC.Integer(2),", " ].concat($this.a().asArray()._, { a: $SC.Integer(5), b: $SC.Integer(6) })));", @@ -4527,8 +4532,8 @@ "max(1, 2, *a)": { compiled: [ "SCScript(function($this, $SC) {", - " var _ref;", - " return (_ref = $SC.Integer(1), _ref.max.apply(_ref, [", + " var _ref0;", + " return (_ref0 = $SC.Integer(1), _ref0.max.apply(_ref0, [", " $SC.Integer(2),", " ].concat($this.a().asArray()._)));", "});", @@ -4669,8 +4674,8 @@ "max(0, *a, a: 3)": { compiled: [ "SCScript(function($this, $SC) {", - " var _ref;", - " return (_ref = $SC.Integer(0), _ref.max.apply(_ref, [" + + " var _ref0;", + " return (_ref0 = $SC.Integer(0), _ref0.max.apply(_ref0, [" + "].concat($this.a().asArray()._, { a: $SC.Integer(3) })));", "});", ], @@ -4740,8 +4745,8 @@ "max(0, *a)": { compiled: [ "SCScript(function($this, $SC) {", - " var _ref;", - " return (_ref = $SC.Integer(0), _ref.max.apply(_ref, [" + + " var _ref0;", + " return (_ref0 = $SC.Integer(0), _ref0.max.apply(_ref0, [" + "].concat($this.a().asArray()._)));", "});", ], @@ -5119,7 +5124,11 @@ "a = (1; 2; 3)": { compiled: [ "SCScript(function($this, $SC) {", - " return $this.a_(($SC.Integer(1), $SC.Integer(2), $SC.Integer(3)));", + " var _ref0;", + " return (_ref0 = " + + "($SC.Integer(1), $SC.Integer(2), $SC.Integer(3)), " + + "$this.a_(_ref0), " + + "_ref0);", "});", ], ast: { @@ -5186,11 +5195,12 @@ "a = (var a = 1; a)": { compiled: [ "SCScript(function($this, $SC) {", - " return $this.a_((function() {", + " var _ref0;", + " return (_ref0 = (function() {", " var $a = $SC.Nil();", " $a = $SC.Integer(1);", " return $a;", - " })());", + " })(), $this.a_(_ref0), _ref0);", "});", ], ast: { @@ -6287,8 +6297,8 @@ "a.value(*[])": { compiled: [ "SCScript(function($this, $SC) {", - " var _ref;", - " return (_ref = $this.a(), _ref.value.apply(_ref, [" + + " var _ref0;", + " return (_ref0 = $this.a(), _ref0.value.apply(_ref0, [" + "].concat($SC.Array([]).asArray()._)));", "});", ], @@ -6922,14 +6932,15 @@ "x = ( a: 1, b: 2, 3: 4 )": { compiled: [ "SCScript(function($this, $SC) {", - " return $this.x_($SC.Event([", + " var _ref0;", + " return (_ref0 = $SC.Event([", " $SC.Symbol('a'),", " $SC.Integer(1),", " $SC.Symbol('b'),", " $SC.Integer(2),", " $SC.Integer(3),", " $SC.Integer(4),", - " ]));", + " ]), $this.x_(_ref0), _ref0);", "});", ], ast: { @@ -7034,14 +7045,15 @@ "x = ( a : 1, b : 2, c : 3 )": { compiled: [ "SCScript(function($this, $SC) {", - " return $this.x_($SC.Event([", + " var _ref0;", + " return (_ref0 = $SC.Event([", " $this.a(),", " $SC.Integer(1),", " $this.b(),", " $SC.Integer(2),", " $this.c(),", " $SC.Integer(3),", - " ]));", + " ]), $this.x_(_ref0), _ref0);", "});", ], ast: { @@ -7143,12 +7155,13 @@ "x = (1 + 2: 3, 4: 5)": { compiled: [ "SCScript(function($this, $SC) {", - " return $this.x_($SC.Event([", + " var _ref0;", + " return (_ref0 = $SC.Event([", " $SC.Integer(1) ['+'] ($SC.Integer(2)),", " $SC.Integer(3),", " $SC.Integer(4),", " $SC.Integer(5),", - " ]));", + " ]), $this.x_(_ref0), _ref0);", "});", ], ast: { @@ -7252,9 +7265,10 @@ "f = _ + _": { compiled: [ "SCScript(function($this, $SC) {", - " return $this.f_($SC.Function(function($_0, $_1) {", + " var _ref0;", + " return (_ref0 = $SC.Function(function($_0, $_1) {", " return $_0 ['+'] ($_1);", - " }));", + " }), $this.f_(_ref0), _ref0);", "});", ], ast: {