UNPKG

fma-snes65816

Version:
301 lines (248 loc) 8.88 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _fma = require('fma'); var _InstructionParameter = require('./InstructionParameter'); var ParameterType = _interopRequireWildcard(_InstructionParameter); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var Code = function () { function Code(code) { (0, _classCallCheck3.default)(this, Code); this.code = code; this.writeUInt8 = this._write({ static: function _static(code, value) { code.writeUInt8(value); }, calc: function calc(code, value) { code.writeCalculation(value, 1); } }); this.writeUInt16 = this._write({ static: function _static(code, value) { code.writeUInt16LE(value); }, calc: function calc(code, value) { code.writeCalculation(value, 2); } }); this.writeUInt24 = this._write({ static: function _static(code, value) { code.writeUInt16LE(value & 0xFFFF); code.writeUInt8(value >> 16); }, calc: function calc(code, value) { code.writeCalculation(value, 3); } }); } (0, _createClass3.default)(Code, [{ key: '_write', value: function _write(callbacks) { var writeStatic = callbacks.static; var writeCalc = callbacks.calc; var code = this.code; return function (number) { if (typeof number === 'number') { writeStatic(code.code, number); } else { switch (number.getClassName()) { case 'Number': writeStatic(code.code, number.getMember('__value').value); break; case 'FutureNumber': writeCalc(code, number.getCalculation()); break; default: throw new Error('Class ' + number.getClassName() + ' can not be written directly'); } } }; } }]); return Code; }(); var Parameter = function () { function Parameter(context, object) { (0, _classCallCheck3.default)(this, Parameter); this.context = context; this.rawValue = object; this.parse(context, object); } (0, _createClass3.default)(Parameter, [{ key: 'toNumber', value: function toNumber(context, object) { if (object.hasMember('to_future_number')) { return object.getMember('to_future_number').callWithParameters(context); } else if (object.hasMember('to_n')) { return object.getMember('to_n').callWithParameters(context); } else { throw new Error('Unknown how to convert to number: ' + object.getClassName()); } } }, { key: 'parse', value: function parse(context, object) { if (object.isNil()) { this.type = ParameterType.NONE; return; } var klass = object.getClassName(); if (klass === 'TypedNumber') { var type = object.getMember('type').getMember('__value').value; this.value = object.getMember('number'); switch (type) { case 'constant': this.type = ParameterType.CONSTANT; break; case 'direct_page': this.type = ParameterType.DP; break; case 'long_address': if (this.value.getClassName() === 'TypedNumber') { var other = new Parameter(context, this.value); this.value = other.value; switch (other.type) { case ParameterType.INDIRECT: this.type = ParameterType.LONG_INDIRECT;break; default: throw new Error('Can not convert: ' + other.type); } } else { this.type = ParameterType.LONG_ADDRESS; return; } break; case 'indirect': var param = object.getMember('parameter').getClassName(); switch (param) { case 'Nil': this.type = ParameterType.INDIRECT;break; case 'Register': var name = object.getMember('parameter').getMember('name').getMember('__value').value; switch (name) { case 'X': this.type = ParameterType.INDIRECT_X;break; case 'Y': this.type = ParameterType.INDIRECT_Y;break; case 'S': this.type = ParameterType.INDIRECT_S;break; default: throw new Error('Unknown register: ' + name); } break; default: throw new Error('Unknown indirect type: ' + param); } break; default: throw new Error('Unknown parameter for instruction: ' + object.getClassName()); } } else if (klass === 'Register') { switch (object.getMember('name').getMember('__value').value) { case 'A': this.type = ParameterType.A;break; case 'X': this.type = ParameterType.X;break; case 'Y': this.type = ParameterType.Y;break; case 'S': this.type = ParameterType.S;break; default: throw new Error('Unknown register'); } } else { this.type = ParameterType.ADDRESS; this.value = this.toNumber(context, object); } } }]); return Parameter; }(); var Instruction = function () { function Instruction(name) { (0, _classCallCheck3.default)(this, Instruction); this.name = name; this.alternatives = {}; } (0, _createClass3.default)(Instruction, [{ key: 'add', value: function add(type, opcode, callback) { if (!this.alternatives.hasOwnProperty(type.p1)) { this.alternatives[type.p1] = {}; } this.alternatives[type.p1][type.p2] = { type: type, opcode: opcode, callback: callback }; } }, { key: 'invoke', value: function invoke(context, p1, p2) { if (!this.alternatives.hasOwnProperty(p1.type) || !this.alternatives[p1.type].hasOwnProperty(p2.type)) { throw new Error('The instruction ' + this.name + ' does not support the given parameters: ' + p1.type + ', ' + p2.type); } var scope = context.getRoot().getObject().getMember('Compiler').getMember('current_scope'); var _alternatives$p1$type = this.alternatives[p1.type][p2.type], type = _alternatives$p1$type.type, opcode = _alternatives$p1$type.opcode, callback = _alternatives$p1$type.callback; if (scope.isUndefined()) { throw new Error('Instructions can only be used within function context'); } scope.setMember('is_return_opcode', new _fma.BooleanObject(false)); var counter = Instruction.getCounter(); var code = new Code(scope.block.code); if (counter) { counter.add(opcode); } type.writer(scope, code, opcode, p1, p2, context); if (callback) { callback(scope, opcode, p1, p2, context); } } }, { key: 'invokeRaw', value: function invokeRaw(context) { var obj = context.getObject(); var p1 = new Parameter(context, obj.getMember('p1')); var p2 = new Parameter(context, obj.getMember('p2')); this.invoke(context, p1, p2); } }, { key: 'build', value: function build() { var _this = this; var macro = new _fma.MacroObject(this.name); var args = new _fma.ArgumentList(); args.addArgument('p1', _fma.ArgumentList.TYPE_ARGUMENT, _fma.Nil); args.addArgument('p2', _fma.ArgumentList.TYPE_ARGUMENT, _fma.Nil); macro.setArguments(args); macro.setCallback(function (context, self) { _this.invokeRaw(context); }); return macro; } }], [{ key: 'getCounter', value: function getCounter() { return Instruction.counter[0] || null; } }, { key: 'pushCounter', value: function pushCounter(counter) { Instruction.counter.unshift(counter); } }, { key: 'popCounter', value: function popCounter() { return Instruction.counter.shift(); } }]); return Instruction; }(); exports.default = Instruction; Instruction.counter = []; //# sourceMappingURL=Instruction.js.map