Skip to content

Commit

Permalink
Refactored code to work in the browser
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Berezin committed May 6, 2019
1 parent 1654d0a commit 3cece04
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 81 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,5 @@ typings/

# next.js build output
.next

dist/
.cache
11 changes: 11 additions & 0 deletions browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { run, Environment } from './index'

const button = document.getElementById('run')
button.onclick = () => {
const code = document.getElementById('code').value
const browserEnv = new Environment()
browserEnv.setBuiltin('alert', (_, arg) => alert(arg[0]))
browserEnv.setBuiltin('confirm', (_, elem) => confirm(elem[0]))
browserEnv.setBuiltin('prompt', (_, p) => prompt(p[0], p.length > 1 ? p[1] : null))
run(code, browserEnv)
}
78 changes: 78 additions & 0 deletions cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#! /usr/bin/env node
const fs = require('fs')
const readline = require('readline')
const Environment = require('./environment')
const { run } = require('./index')

let options = {
debug: false,
history: 30,
prompt: '>'
}

const runPrompt = () => {
const prompt = options.prompt + ' '
process.stdout.write(prompt)
const lineReader = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: true,
prompt: prompt,
historySize: +options.history
})
const env = new Environment()
env.setBuiltin('readFile', (_vars, args) => fs.readFileSync(args[0], 'utf8'))

lineReader.on('line', line => {
let code = line
if (!line.endsWith(';') && !line.endsWith('}')) code += ';'
// TODO: Support multi-line block statements
const lastLine = run(code, env, options.debug)
console.log(JSON.stringify(lastLine))
process.stdout.write(prompt)
})
}

const runFile = filename => {
try {
const file = fs.readFileSync(filename, 'utf8')
run(file, undefined, options.debug)
} catch (e) {
console.error(`YALI could not read the file ${filename}`)
console.error(e)
}
}

const optionRegex = /--(\w+)(?:=(.+))?/
const processOptions = args =>
args
.map(arg => {
const match = optionRegex.exec(arg)
if (match) {
const [_, option, value] = match
if (!value) {
options[option] = !options[option]
} else {
options[option] = value
}
} else {
return arg
}
})
.filter(Boolean)

const main = argv => {
process.title = 'YALI'
const args = processOptions(argv.slice(2))
if (options.debug) console.log(options)
if (args.length > 1) {
console.error('Usage: jlox [script]')
return 64
} else if (args.length === 1) {
runFile(args[0])
} else {
runPrompt()
}
}

return main(process.argv)
27 changes: 27 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>YALI.js</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<textarea id="code" cols="50" rows="15">
var a = 0;
var b = 1;
var limit = prompt("Limit to find fib numbers", 10000);

while (a < limit) {
print a;
var temp = a;
a = b;
b = temp + b;
}</textarea>
<br>
<button id="run">
Run
</button>
<script src="browser.js"></script>
</body>
</html>
85 changes: 7 additions & 78 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,18 @@
#! /usr/bin/env node
const fs = require('fs')
const chalk = require('chalk')
const readline = require('readline')
const Tokenizer = require('./tokenizer')
const Parser = require('./parser')
const { LoxError } = require('./errors')
const Interpreter = require('./interpreter')
const Environment = require('./environment')

let options = {
debug: false,
history: 30,
prompt: '>'
}

const run = (code, environment) => {
const run = (code, environment, debug = false) => {
try {
const tokenizer = new Tokenizer(code)
const tokens = tokenizer.scanTokens()
if (options.debug) console.log(tokens)
if (debug) console.log(tokens)
const parser = new Parser(tokens)
const statements = parser.parse()
if (options.debug) console.log(statements)
if (debug) console.log(statements)
const interpreter = new Interpreter(environment)
let lastStatement
for (let statement of statements) {
Expand Down Expand Up @@ -59,69 +50,7 @@ const run = (code, environment) => {
}
}

const runPrompt = () => {
const prompt = options.prompt + ' '
process.stdout.write(prompt)
const lineReader = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: true,
prompt: prompt,
historySize: +options.history
})
const env = new Environment()
env.setBuiltin('readFile', (_vars, args) => fs.readFileSync(args[0], 'utf8'))

lineReader.on('line', line => {
let code = line
if (!line.endsWith(';') && !line.endsWith('}')) code += ';'
// TODO: Support multi-line block statements
const lastLine = run(code, env)
console.log(JSON.stringify(lastLine))
process.stdout.write(prompt)
})
}

const runFile = filename => {
try {
const file = fs.readFileSync(filename, 'utf8')
run(file)
} catch (e) {
console.error(`YALI could not read the file ${filename}`)
console.error(e)
}
}

const optionRegex = /--(\w+)(?:=(.+))?/
const processOptions = args =>
args
.map(arg => {
const match = optionRegex.exec(arg)
if (match) {
const [_, option, value] = match
if (!value) {
options[option] = !options[option]
} else {
options[option] = value
}
} else {
return arg
}
})
.filter(Boolean)

const main = argv => {
process.title = 'YALI'
const args = processOptions(argv.slice(2))
if (options.debug) console.log(options)
if (args.length > 1) {
console.error('Usage: jlox [script]')
return 64
} else if (args.length === 1) {
runFile(args[0])
} else {
runPrompt()
}
}

return main(process.argv)
module.exports = {
run,
Environment
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"name": "yali",
"version": "1.0.0",
"version": "0.10.2",
"description": "Yet Another Lox Interpreter. Javascript Implementation of the Lox Programming Language",
"main": "index.js",
"bin": "./index.js",
"bin": "./cli.js",
"scripts": {
"test": "jest",
"format": "prettier --write **/*.js",
Expand Down

0 comments on commit 3cece04

Please sign in to comment.