diff --git a/README.md b/README.md index ccf28e9..1ed79db 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,76 @@ # YALI.js - ### Yet Another Lox Interpreter. Javascript Implementation Lox is a Dynamically Typed Programming Language created by [Bob Nystrom](https://twitter.com/intent/user?screen_name=munificentbob) for his excellent book [Crafting Interpreters](https://craftinginterpreters.com). This is yet another Javascript Implementation. -## [Try it out!](https://danman113.github.io/YALI.js/) +## [Try it out in the Playground!](https://danman113.github.io/YALI.js/) + + +## Installation + +```bash +$ npm install yali.js +``` + +## CLI Usage + +### File +```bash +$ yali loxfile.lox +``` + +### REPL +```bash +$ yali +> print "No semicolons needed!" +``` + +### loxfmt +```bash +$ loxfmt --write --indent=" " loxfile.lox +``` + +### lox2python +```bash +$ lox2python loxfile.lox --out="a.py" +``` +**OR** +```bash +$ lox2python loxfile.lox | python +``` + +## Embedding in your JS App +The main interface of YALI.js is a `run` method that will tokenize, parse, and interpret your lox source code, all in one function. +```javascript +run(source_code, environment = new Environment(), printfn = console.log, debug = false) +``` + +You can pass in an `environment` object, which lets you define built-in variables and functions like so: +```javascript +const { run, Environment } = require('yali') +const env = new Environment() +env.setBuiltin('owner', 'dberezin') +env.setBuiltin('meaning_of_life', 42) +env.setBuiltin('alert', (interpreter, arg) => alert(arg[0])) +``` + +You can also pass in a `printfn` that will be called for every `print` statement. Here's an example for capitalizing each word in the stdout: +```javascript +run( + 'print "hello world";', + new Environment(), + out => console.log(out.split(' ').map(_.capitalize).join(' ')) +) +> Hello World +``` + +## Parsing +YALI.js also provides a `parse` function to tokenize and parse lox source code, returning an array of AST nodes that can be manipulated as desired. See any of the [transpiler examples](./transpilers/python) for reference. + + +## Contribute + +For any bugs and feature requests please [open an issue](https://github.com/danman113/YALI.js/issues). For code contributions please create a [pull request](https://github.com/danman113/YALI.js/pulls). Enjoy! + diff --git a/examples/performance.lox b/examples/performance.lox new file mode 100644 index 0000000..4402374 --- /dev/null +++ b/examples/performance.lox @@ -0,0 +1,9 @@ +fun fib(n) { + if (n < 2) return n; + return fib(n - 1) + fib(n - 2); +} + +var before = clock(); +print fib(25); +var after = clock(); +print after - before; \ No newline at end of file diff --git a/index.js b/index.js index 34c5b04..c9da5f9 100755 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ const Tokenizer = require('./tokenizer') const Parser = require('./parser') -const Interpreter = require('./interpreter') +const { Interpreter, LoxClass, LoxInstance } = require('./interpreter') const Environment = require('./environment') const run = (code, environment, printfn, debug = false) => { @@ -29,5 +29,10 @@ const parse = code => { module.exports = { run, parse, + Parser, + LoxClass, + Tokenizer, + LoxInstance, + Interpreter, Environment } diff --git a/interpreter.js b/interpreter.js index 97b50af..017b73a 100644 --- a/interpreter.js +++ b/interpreter.js @@ -385,4 +385,8 @@ class Interpreter { } } -module.exports = Interpreter +module.exports = { + Interpreter, + LoxClass, + LoxInstance +} diff --git a/interpreter.test.js b/interpreter.test.js index c5bc026..d41c62b 100644 --- a/interpreter.test.js +++ b/interpreter.test.js @@ -1,4 +1,4 @@ -const Interpreter = require('./interpreter') +const { Interpreter } = require('./interpreter') const Tokenizer = require('./tokenizer') const Parser = require('./parser') diff --git a/transpilers/lox.js b/transpilers/lox.js index 7a28464..7524b23 100644 --- a/transpilers/lox.js +++ b/transpilers/lox.js @@ -162,7 +162,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`, node.constructor) + throw new Error(`Don't support classes yet`) } module.exports = {