From e37a1e3a6d1e20bace92658d3f17e0a0571e73dc Mon Sep 17 00:00:00 2001 From: Daniel Berezin Date: Mon, 24 Jun 2019 20:16:38 -0700 Subject: [PATCH] Added classes to loxfmt --- browser.js | 1 + docs/browser.e9f8be96.js | 2 +- transpilers/lox.js | 48 ++++++++++++++++++++++++++++++++++------ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/browser.js b/browser.js index 2b3bd2f..49a2dfe 100644 --- a/browser.js +++ b/browser.js @@ -97,6 +97,7 @@ formatButton.onclick = () => { try { const ast = parse(code.value) global.ast = ast + // console.log(ast.map(stmt => printLoxAST(stmt)).join('\n')) code.value = ast.map(stmt => printLoxAST(stmt)).join('\n') handleError(null) } catch (e) { diff --git a/docs/browser.e9f8be96.js b/docs/browser.e9f8be96.js index c112cc1..1754675 100644 --- a/docs/browser.e9f8be96.js +++ b/docs/browser.e9f8be96.js @@ -13,7 +13,7 @@ function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterat },{"./errors":"p8GN","./types":"39eF","./environment":"brut","./tokenizer":"u74b"}],"Focm":[function(require,module,exports) { var e=require("./tokenizer"),r=require("./parser"),n=require("./interpreter"),t=n.Interpreter,o=n.LoxClass,a=n.LoxInstance,i=require("./environment"),s=function(n,o,a){var i=arguments.length>3&&void 0!==arguments[3]&&arguments[3],s=new e(n).scanTokens();i&&console.log(s);var l=new r(s).parse();i&&console.log(l);var u,v=new t(o,a),c=!0,p=!1,f=void 0;try{for(var w,x=l[Symbol.iterator]();!(c=(w=x.next()).done);c=!0){var y=w.value;u=v.interpret(y)}}catch(d){p=!0,f=d}finally{try{c||null==x.return||x.return()}finally{if(p)throw f}}return u},l=function(n){var t=new e(n).scanTokens();return new r(t).parse()};module.exports={run:s,parse:l,Parser:r,LoxClass:o,Tokenizer:e,LoxInstance:a,Interpreter:t,Environment:i}; },{"./tokenizer":"u74b","./parser":"CUYV","./interpreter":"lmrS","./environment":"brut"}],"9/6S":[function(require,module,exports) { -function n(n){return r(n)||e(n)||t()}function t(){throw new TypeError("Invalid attempt to spread non-iterable instance")}function e(n){if(Symbol.iterator in Object(n)||"[object Arguments]"===Object.prototype.toString.call(n))return Array.from(n)}function r(n){if(Array.isArray(n)){for(var t=0,e=new Array(n.length);t1&&void 0!==arguments[1]?arguments[1]:" ";return n?t:""},w=new Map;w.set(g,function(n,t,e){return E(n.expression,0,e)+("forLoop"===n.context?"":";")}),w.set(v,function(n){return"print "+E(n.expression)+";"}),w.set(p,function(n){return"return "+E(n.value)+";"}),w.set(d,function(n){var t=n.name.lexeme,e=n.initializer?E(n.initializer):null;return"var ".concat(t)+(e?" = ".concat(e):"")+";"}),w.set(j,function(n,t,e){var r=n.condition,o=n.thenBranch,a=n.elseBranch,c=E(r),i="if".concat(b(e.spaceBeforeParams),"(").concat(c,") "),u=E(o,t,e,!1),s=a&&E(a,t,e,!1);return i+u+(s?" else ".concat(s):"")}),w.set(m,function(t,e,r){var o=t.bodyStatements,a=t.name.lexeme,c=t.params.map(function(n){return n.lexeme}),i="fun ".concat(a).concat(b(r.spaceBeforeParams),"(").concat(c.join(", "),") {"),u=o.map(function(n){return E(n,e+1,r)}),s=r.indent.repeat(e)+"}"+b(r.functionNewlines,"\n");return[i].concat(n(u),[s]).join("\n")});var B=function(n,t,e){var r=n.body,o=n.condition,a=E(o);return"while".concat(b(e.spaceBeforeParams),"(").concat(a,") ")+E(r,t,e,!1)},L=function(n,t,e){var r=n.body,o=n.condition,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:";",c="forLoop"!==o.context?E(o):"",i="",u=r;if(r instanceof y&&"forLoop"===r.context){var s=r.statements;u=s[0],s.length>1&&(i=E(s[s.length-1],t,e,!1))}var f=E(u,t,e,!1),l=[c,i];return"for".concat(b(e.spaceBeforeParams),"(").concat(a," ").concat(l.join("; "),") ").concat(f)};w.set(f,function(n,t,e){return"forLoop"===n.context?L(n,t,e):B(n,t,e)});var A=function(n,t,e){var r=n.statements,o=E(r[0],t,e,!1);return L(r[1],t,e,o)},S=function(n,t,e){return"{\n"+n.statements.map(function(n){return E(n,t+1,e)}).join("\n")+"\n".concat(e.indent.repeat(t),"}")};w.set(y,function(n,t,e){return"forLoop"===n.context?A(n,t,e):S(n,t,e)}),w.set(i,function(n){return n.name.lexeme}),w.set(l,function(n){var t=n.expression;return"("+E(t)+")"});var P=function(n){return[E(n.left),n.operator.lexeme,E(n.right)].join(" ")};w.set(a,P),w.set(x,P),w.set(c,function(n){return n.operator.lexeme+E(n.right)}),w.set(u,function(n){var t=n.arguments.map(function(n){return E(n)}).join(", "),e=E(n.callee);return"".concat(e,"(").concat(t,")")}),w.set(h,function(n){return n.name.lexeme+" = "+E(n.value)}),w.set(s,function(n){var t=n.value;return"string"==typeof t?'"'.concat(t,'"'):null===t?"nil":t});var E=function(n){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,e=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=!(arguments.length>3&&void 0!==arguments[3])||arguments[3],o=Object.assign({},{indent:"\t",spaceBeforeParams:!0,functionNewlines:!0},e);if(w.has(n.constructor))return(r?o.indent.repeat(t):"")+w.get(n.constructor)(n,t,o);throw new Error("Don't support classes yet")};module.exports={printLoxAST:E}; +function n(n){return r(n)||t(n)||e()}function e(){throw new TypeError("Invalid attempt to spread non-iterable instance")}function t(n){if(Symbol.iterator in Object(n)||"[object Arguments]"===Object.prototype.toString.call(n))return Array.from(n)}function r(n){if(Array.isArray(n)){for(var e=0,t=new Array(n.length);e1&&void 0!==arguments[1]?arguments[1]:" ";return n?e:""},P=new Map;P.set(j,function(n,e,t){return G(n.expression,0,t)+("forLoop"===n.context?"":";")}),P.set(y,function(n){return"print "+G(n.expression)+";"}),P.set(h,function(n){return"return "+G(n.value)+";"}),P.set(b,function(n){var e=n.name.lexeme,t=n.initializer?G(n.initializer):null;return"var ".concat(e)+(t?" = ".concat(t):"")+";"}),P.set(w,function(n,e,t){var r=n.condition,o=n.thenBranch,a=n.elseBranch,c=G(r),i="if".concat(A(t.spaceBeforeParams),"(").concat(c,") "),u=G(o,e,t,!1),s=a&&G(a,e,t,!1);return i+u+(s?" else ".concat(s):"")});var C=function(e,t,r){var o=e.bodyStatements,a=e.name.lexeme,c=e.params,i=!(arguments.length>3&&void 0!==arguments[3])||arguments[3],u=c.map(function(n){return n.lexeme}),s=(i?"fun ":"")+"".concat(a).concat(A(r.spaceBeforeParams),"(").concat(u.join(", "),") {"),f=o.map(function(n){return G(n,t+1,r)}),l=r.indent.repeat(t)+"}"+A(r.functionNewlines,"\n");return[s].concat(n(f),[l]).join("\n")};P.set(g,C);var O=function(n,e,t){var r=n.body,o=n.condition,a=G(o);return"while".concat(A(t.spaceBeforeParams),"(").concat(a,") ")+G(r,e,t,!1)},T=function(n,e,t){var r=n.body,o=n.condition,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:";",c="forLoop"!==o.context?G(o):"",i="",u=r;if(r instanceof S&&"forLoop"===r.context){var s=r.statements;u=s[0],s.length>1&&(i=G(s[s.length-1],e,t,!1))}var f=G(u,e,t,!1),l=[c,i];return"for".concat(A(t.spaceBeforeParams),"(").concat(a," ").concat(l.join("; "),") ").concat(f)};P.set(f,function(n,e,t){return"forLoop"===n.context?T(n,e,t):O(n,e,t)}),P.set(l,function(e,t,r){var o=e.name,a=e.superclass,c=e.methods,i="";if(a){var u=a.name.lexeme;i=" < ".concat(u)}var s="class ".concat(o.lexeme).concat(i," {"),f=r.indent.repeat(t)+"}",l=c.map(function(n){return r.indent.repeat(t+1)+C(n,t+1,r,!1)});return[s].concat(n(l),[f]).join("\n")}),P.set(m,function(n,e,t){var r=n.name,o=n.object,a=r.lexeme?r.lexeme:G(r,e,t,!1);return G(o,e,t,!1)+"."+a}),P.set(p,function(n,e,t){var r=n.name,o=n.object,a=n.value,c=r.lexeme?r.lexeme:G(r,e,t,!1);return G(o,e,t,!1)+"."+c+" = "+G(a,e,t)}),P.set(v,function(n){var e=n.method.lexeme;return"super.".concat(e)}),P.set(x,function(n){return n.keyword.lexeme});var k=function(n,e,t){var r=n.statements,o=G(r[0],e,t,!1);return T(r[1],e,t,o)},z=function(n,e,t){return"{\n"+n.statements.map(function(n){return G(n,e+1,t)}).join("\n")+"\n".concat(t.indent.repeat(e),"}")};P.set(S,function(n,e,t){return"forLoop"===n.context?k(n,e,t):z(n,e,t)}),P.set(i,function(n){return n.name.lexeme}),P.set(d,function(n){var e=n.expression;return"("+G(e)+")"});var E=function(n){return[G(n.left),n.operator.lexeme,G(n.right)].join(" ")};P.set(a,E),P.set(L,E),P.set(c,function(n){return n.operator.lexeme+G(n.right)}),P.set(u,function(n){var e=n.arguments.map(function(n){return G(n)}).join(", "),t=G(n.callee);return"".concat(t,"(").concat(e,")")}),P.set(B,function(n){return n.name.lexeme+" = "+G(n.value)}),P.set(s,function(n){var e=n.value;return"string"==typeof e?'"'.concat(e,'"'):null===e?"nil":e});var G=function(n){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=!(arguments.length>3&&void 0!==arguments[3])||arguments[3],o=Object.assign({},{indent:"\t",spaceBeforeParams:!0,functionNewlines:!0},t);if(P.has(n.constructor))return(r?o.indent.repeat(e):"")+P.get(n.constructor)(n,e,o)};module.exports={printLoxAST:G}; },{"../types":"39eF"}],"KVVd":[function(require,module,exports) { },{}],"3hpa":[function(require,module,exports) { diff --git a/transpilers/lox.js b/transpilers/lox.js index 7524b23..e929c43 100644 --- a/transpilers/lox.js +++ b/transpilers/lox.js @@ -6,9 +6,11 @@ const { Literal, While, // @TODO: Support Classes - // Class, - // Get, - // Set, + Class, + Get, + Set: SetExpr, + Super, + This, Grouping, Return, LoxFunction, @@ -46,14 +48,16 @@ ASTNodeMap.set(Condition, ({ condition, thenBranch, elseBranch }, scope, options return conditionSection + thenSection + (elseSection ? ` else ${elseSection}` : '') }) -ASTNodeMap.set(LoxFunction, ({ bodyStatements: body, name: { lexeme: name }, params}, scope, options) => { +const printFunction = ({ bodyStatements: body, name: { lexeme: name }, params}, scope, options, func = true) => { const parameters = params.map(token => token.lexeme) - const head = `fun ${name}${condChar(options.spaceBeforeParams)}(${parameters.join(', ')}) {` + const id = func ? 'fun ' : '' + const head = id + `${name}${condChar(options.spaceBeforeParams)}(${parameters.join(', ')}) {` const fnBody = body.map(stmt => printLoxAST(stmt, scope + 1, options)) const tail = options.indent.repeat(scope) + '}' + condChar(options.functionNewlines, '\n') return [head, ...fnBody, tail].join('\n') -}) +} +ASTNodeMap.set(LoxFunction, printFunction) const handleWhileLoop = ({ body, condition }, scope, options) => { const cond = printLoxAST(condition) @@ -86,6 +90,36 @@ ASTNodeMap.set(While, (node, scope, options) => { } }) +ASTNodeMap.set(Class, ({ name, superclass, methods }, scope, options) => { + let superclassStr = '' + if (superclass) { + const superClassName = superclass.name.lexeme + superclassStr = ` < ${superClassName}` + } + const head = `class ${name.lexeme}${superclassStr} {` + const tail = options.indent.repeat(scope) + '}' + let body = methods.map(node => options.indent.repeat(scope + 1) + printFunction(node, scope + 1, options, false)) + return [head, ...body, tail].join('\n') +}) + +ASTNodeMap.set(Get, ({ name, object }, scope, options) => { + const nameStr = name.lexeme ? name.lexeme : printLoxAST(name, scope, options, false) + const objectStr = printLoxAST(object, scope, options, false) + return objectStr + '.' + nameStr +}) + +ASTNodeMap.set(SetExpr, ({ name, object, value }, scope, options) => { + const nameStr = name.lexeme ? name.lexeme : printLoxAST(name, scope, options, false) + const objectStr = printLoxAST(object, scope, options, false) + const val = printLoxAST(value, scope, options) + return objectStr + '.' + nameStr + ' = ' + val +}) + +ASTNodeMap.set(Super, ({ method: { lexeme: methodName }}) => { + return `super.${methodName}` +}) + +ASTNodeMap.set(This, ({ keyword }) => keyword.lexeme) const blockForLoop = ({ statements }, scope, options) => { const iter = printLoxAST(statements[0], scope, options, false) @@ -162,7 +196,7 @@ const printLoxAST = (node, scope = 0, optionsOverride = {}, initialIndent = true const indentation = (initialIndent ? options.indent.repeat(scope) : '') return indentation + ASTNodeMap.get(node.constructor)(node, scope, options) } - throw new Error(`Don't support classes yet`) + // throw new Error(`Don't support classes yet`) } module.exports = {