Skip to content

Commit

Permalink
Added builtin function calls
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Berezin committed May 6, 2019
1 parent 5c5afe4 commit 1654d0a
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 5 deletions.
4 changes: 4 additions & 0 deletions environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ class Environment {
return this.map.set(token.lexeme, value)
}

setBuiltin(name, func) {
this.map.set(name, typeof func === 'function' ? { call: func } : func)
}

assign(token, value) {
if (!this.map.has(token.lexeme)) {
if (this.enclosing) return this.enclosing.assign(token, value)
Expand Down
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const run = (code, environment) => {
// Error String
const errorSection = code.substr(e.startCoordinates.index, e.endCoordinates.index)

// @TODO: Fix this
// Post Error String
const backIndex = code.indexOf('\n', e.endCoordinates.index)
const postErrorStart = backIndex < 0 ? code.length : backIndex
Expand All @@ -69,6 +70,7 @@ const runPrompt = () => {
historySize: +options.history
})
const env = new Environment()
env.setBuiltin('readFile', (_vars, args) => fs.readFileSync(args[0], 'utf8'))

lineReader.on('line', line => {
let code = line
Expand Down Expand Up @@ -109,6 +111,7 @@ const processOptions = args =>
.filter(Boolean)

const main = argv => {
process.title = 'YALI'
const args = processOptions(argv.slice(2))
if (options.debug) console.log(options)
if (args.length > 1) {
Expand Down
20 changes: 20 additions & 0 deletions interpreter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const { runtimeError } = require('./errors')
const {
Binary,
Unary,
Call,
Literal,
Logical,
Var,
Expand Down Expand Up @@ -31,6 +32,12 @@ const checkNumber = (token, ...operands) => {
class Interpreter {
constructor(environment) {
this.environment = environment || new Environment()
this.environment.setBuiltin('PI', Math.PI)
this.environment.setBuiltin('cos', (_vars, args) => Math.cos(args[0]))
this.environment.setBuiltin('mod', (_vars, args) => args[0] % args[1])
this.environment.setBuiltin('strlen', (_vars, args) => args[0].length)
this.environment.setBuiltin('charAt', (_vars, args) => args[0][args[1]])
this.environment.setBuiltin('clock', () => new Date().getTime())
}

interpret(expr) {
Expand All @@ -41,6 +48,7 @@ class Interpreter {
if (expr instanceof Block) return this.visitBlock(expr)
else if (expr instanceof Assignment) return this.visitAssignment(expr)
else if (expr instanceof Logical) return this.visitLogical(expr)
else if (expr instanceof Call) return this.visitCall(expr)
else if (expr instanceof While) return this.visitWhile(expr)
else if (expr instanceof Condition) return this.visitCondition(expr)
else if (expr instanceof VarStatement) return this.visitVarStatement(expr)
Expand Down Expand Up @@ -130,6 +138,18 @@ class Interpreter {
return value
}

visitCall(expr) {
const callee = this.evaluate(expr.callee)

let args = expr.arguments.map(arg => this.evaluate(arg))

if (!callee.call) {
throw runtimeError('Can only call functions and classes', expr.paren)
}

return callee.call(this, args)
}

visitUnary(expr) {
const right = this.evaluate(expr.right)
switch (expr.operator.type) {
Expand Down
31 changes: 27 additions & 4 deletions parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const {
Binary,
Unary,
Var,
Call,
Literal,
While,
Grouping,
Expand Down Expand Up @@ -75,7 +76,6 @@ class Parser {
return this.matchBinary('equality', Logical, token.AND)
}


varDeclaration() {
const name = this.consume(token.IDENTIFIER, 'Expected variable name')
let initializer = null
Expand All @@ -87,8 +87,7 @@ class Parser {
return new VarStatement(name, initializer)
}


forStatement () {
forStatement() {
this.consume(token.LEFT_PAREN, 'Expected "(" after "for"')

let init
Expand Down Expand Up @@ -204,7 +203,31 @@ class Parser {
const right = this.unary()
return new Unary(operator, right)
}
return this.primary()
return this.call()
}

call() {
let expr = this.primary()
while (true) {
if (this.match(token.LEFT_PAREN)) {
expr = this.finishCall(expr)
} else {
break
}
}

return expr
}

finishCall(callee) {
let args = []
if (!this.check(token.RIGHT_PAREN)) {
do {
args.push(this.expression())
} while (this.match(token.COMMA))
}
const paren = this.consume(token.RIGHT_PAREN, 'Unfinished argument list')
return new Call(callee, paren, args)
}

primary() {
Expand Down
21 changes: 20 additions & 1 deletion types.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ class Var {
}
}

// @TODO: Can we express this in a less type-dependant way?
class Grouping {
constructor(expression) {
this.expression = expression
Expand Down Expand Up @@ -72,11 +71,31 @@ class While {
}
}

class Call {
constructor(callee, paren, args) {
;(this.callee = callee), (this.paren = paren)
this.arguments = args
}
}

class Callable {
constructor(name, func) {
this.lexeme = name
this.call = func
}

toString() {
return '<native fn>'
}
}

module.exports = {
Var,
Binary,
Unary,
Block,
Call,
Callable,
While,
Literal,
Logical,
Expand Down

0 comments on commit 1654d0a

Please sign in to comment.