Skip to content

Commit

Permalink
refactor: improve support for built-in objects
Browse files Browse the repository at this point in the history
  • Loading branch information
LuanRT committed Aug 26, 2022
1 parent 0373c8f commit 3d6d328
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 17 deletions.
63 changes: 48 additions & 15 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Visitor from './visitor';
import { parse } from 'acorn';

export default class Jinter {
private ast: any;

Expand All @@ -14,23 +14,56 @@ export default class Jinter {

this.visitor = new Visitor(this.ast);
this.scope = this.visitor.scope;

this.visitor.on('console', (node: any, visitor: Visitor) => {
if (node.type === 'Identifier')
return console;

const prop: keyof Console = visitor.visitNode(node.callee.property);
const args = node.arguments.map((arg: any) => visitor.visitNode(arg));

const console_prop = console[prop] as Function;

if (!console_prop)
return 'proceed';

return console_prop(...args);
});

const console_polyfill = {
log: (args: any[]) => console.log(...args)
}

const string_polyfill = {
fromCharCode: (num: number) => String.fromCharCode(num)
};
this.visitor.on('Math', (node: any, visitor: Visitor) => {
if (node.type === 'Identifier')
return Math;

const prop: keyof Math = visitor.visitNode(node.callee.property);
const args = node.arguments.map((arg: any) => visitor.visitNode(arg));

const math_prop = Math[prop] as Function;

if (!math_prop)
return 'proceed';

return math_prop(...(args as [ number, number ]));
});

const math_polyfill = {
pow: (args: [ number, number ]) => Math.pow(...args)
}
this.visitor.on('String', (node: any, visitor: Visitor) => {
if (node.type === 'Identifier')
return String;

const prop: keyof typeof String = visitor.visitNode(node.callee.property);
const args = node.arguments.map((arg: any) => visitor.visitNode(arg));

const string_prop = String[prop] as Function;

if (!string_prop)
return 'proceed';

return string_prop(args);
});

this.scope.set('console', console_polyfill);
this.scope.set('String', string_polyfill);
this.scope.set('Math', math_polyfill);
this.scope.set('Date', Date);
this.visitor.on('Date', (node: any) => {
if (node.type === 'Identifier')
return Date;
});
}

public interpret() {
Expand Down
3 changes: 2 additions & 1 deletion src/nodes/BlockStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export default class BlockStatement {
if (
(stmt.type === 'WhileStatement' ||
stmt.type === 'IfStatement' ||
stmt.type === 'ForStatement') &&
stmt.type === 'ForStatement' ||
stmt.type === 'TryStatement') &&
!!result
) {
return result;
Expand Down
16 changes: 16 additions & 0 deletions src/nodes/CallExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@ import Visitor from '../visitor';

export default class CallExpression {
static visit(node: any, visitor: Visitor) {
const obj_name = node.callee.object?.name;
const fn_name = node.callee.name || node.callee.property?.name;

// Obj.fn(...);
if (visitor.listeners[obj_name]) {
const cb = visitor.listeners[obj_name](node, visitor);
if (cb !== 'proceed') {
return cb;
}
}

// ?.fn(...);
if (visitor.listeners[fn_name]) {
const cb = visitor.listeners[fn_name](node, visitor);
if (cb !== 'proceed') {
Expand Down Expand Up @@ -92,6 +102,12 @@ export default class CallExpression {
throw new Error(`${callee} is not a function`);
} else {
const args = node.arguments.map((arg: any) => visitor.visitNode(arg));

if (callee.toString().includes('[native code]')) {
const obj = visitor.visitNode(node.callee.object);
return obj[node.callee.property.name]();
}

return callee(args);
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/nodes/Identifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ import Visitor from '../visitor';
export default class Identifier {
static visit(node: any, visitor: Visitor) {
if (visitor.listeners[node.name]) {
return visitor.listeners[node.name](node, visitor);
const cb = visitor.listeners[node.name](node, visitor);
if (cb !== 'proceed') {
return cb;
}
}

if (visitor.scope.has(node.name))
return visitor.scope.get(node.name);

return node.name;
}
}

0 comments on commit 3d6d328

Please sign in to comment.