Skip to content
This repository was archived by the owner on Aug 26, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
077a503
Formatted JS files with Standard style
Oct 28, 2019
20e111b
Separate test cases for each fixture file
Oct 28, 2019
ecbb186
Rework of the compiler, initial fixtures
Oct 29, 2019
66be5ff
Switch from classes to functions, much cleaner and more composable
Oct 30, 2019
4cc95c4
Refactored switch-case conversion to a mapper-object
Oct 30, 2019
4dca368
Tiny reformat
Oct 30, 2019
2c46980
New test case for multiple function declarations, renamed 001 accordi…
Oct 30, 2019
ff3845a
Remove the failing test cases for now
Oct 30, 2019
fb9ff1a
Support for ints, more reorg for fixture files
Oct 30, 2019
1151d86
Preliminary string concatenation support
Oct 30, 2019
fc033c0
Int.plus supported
Oct 30, 2019
4f0c3c0
Int-multiply supported
Oct 30, 2019
9329af6
String-concat monoid associativity
Oct 30, 2019
88cae4b
Tests for binary integer op's associativity and precendence
Oct 30, 2019
68a6e89
Initial suppport for call expressions
Oct 30, 2019
41a8515
Introduce scopes to track ambient hierarchy
Oct 30, 2019
c4c9f9d
Organized the index.js to separate files
Oct 30, 2019
5dd7b84
AST elements now return intermediary objects instead of strings
Nov 5, 2019
131d989
Separate optimize-step for manipulating ambients-AST before algebra t…
Nov 5, 2019
1eadb70
Renamed toAlgebra(scope) to toAmbients(scope)
Nov 5, 2019
f062def
Removed commented code
Nov 5, 2019
45b68dc
Removed unused scope-field
Nov 5, 2019
d9100c9
Refactored algebra-AST classes to closures
Nov 6, 2019
00dc9fe
Moved algebra-ast functions to own file
Nov 6, 2019
838018e
Moved literal, verifyprimitives to primitives.js
Nov 6, 2019
fdcba62
Fixed the parallel.optimize
Nov 6, 2019
205617a
Support for (x) => x
Nov 6, 2019
8f91ad8
Cleanup, refactoring, renaming
Nov 6, 2019
62a0344
Non-working support for returning functions
Nov 7, 2019
525a832
Better names in index.js
Nov 8, 2019
646fc61
AST mapper to operate top-down
Nov 8, 2019
80b9c63
Functions returning functions now are encoded with func-primitives
Nov 8, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/algebra_ast.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const seq = (...args) => ({
toAlgebra: () => args.map(optimizeStep).map(toAlgebra).filter(nonEmptyExpressions).join('.')
})

const parallel = (...args) => ({
type: 'parallel',
args: args,
optimize: () => {
const parallelArgs = args.filter(arg => arg.type === 'parallel')
if (parallelArgs.length === args.length) {
return parallel(...parallelArgs.map(arg => arg.args).reduce((arr, a) => arr.concat(a), []))
}
return parallel(...args)
},
toAlgebra: () => {
let parallelPrograms = args.map(optimizeStep).map(toAlgebra).filter(nonEmptyExpressions)
if (parallelPrograms.length > 1) {
return `(${parallelPrograms.join('|')})`
}

return parallelPrograms.join('|')
}

})

const ambient = (name, ...args) => ({
toAlgebra: () => {
return `${name}[${args.map(optimizeStep).map(toAlgebra).filter(nonEmptyExpressions).join('|')}]`
}
})

const optimizeStep = node => node.optimize === undefined ? node : node.optimize()
const toAlgebra = node => node.toAlgebra === undefined ? node.toString() : node.toAlgebra()
const nonEmptyExpressions = string => string.length > 0

module.exports = {ambient, seq, parallel}
130 changes: 130 additions & 0 deletions src/ambients_ast.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
const { literal, verifyPrimitive } = require('./primitives.js')
const { ambient, seq, parallel } = require('./algebra_ast.js')

const parameterDeclaration = (name) => ({
toAmbient: (scope) => {
return ambient(name, 'in_ arg.open arg.open_')
}
})
const variableExpression = (name) => ({
toAmbient: (scope) => {
return `open ${name}`
}
})
const binaryExpression = (left, right, operator) => {
let primitive = verifyPrimitive(left, right)
switch (operator) {
case '+':
return primitive.plus(left, right)
case '*':
return primitive.multiply(left, right)
default:
throw new Error(`Operator '${operator}' is not supported`)
}

}

const callExpression = (functionName) => ({
toAmbient: (scope) => {
return scope.functionCall(functionName)
}
})

const funcEnvelope = (expression) => ({
toAmbient: (scope) => {
return ambient('func',
expression.toAmbient(scope),
'open_')
}
})

const functionExpression = (args, expression) => ({
toAmbient: (scope) => {
return parallel(
scope.functionArgs(args),
expression.toAmbient(scope))
}
})

const functionDefinition = (name, body) => ({
toAmbient: (scope) => {
let newScope = scope.newScope(name)
return ambient(name,
newScope.capabilities(),
seq('in_ call.open call', parallel(
body.toAmbient(newScope),
'open return.open_'
))
)
}
})

const programFile = (declarations, resultStatement) => ({
toAmbient: (scope) => {
const algebra = declarations
.map(declaration => declaration.toAmbient(scope).toAlgebra())
.map(code => code.replace(/\r?\n\s*|\r\s*/g, '').replace(/\s+/g, ' '))
.join('|')
return algebra
}
})

class Scope {
constructor (name, parentScope) {
this._name = name
this._parentScope = parentScope
this._auths = []
}

functionArgs (args) {
return parallel(...args.map(arg => arg.toAmbient(this)))
}

functionCall (functionName) {
let scopesToPass = this.allow('call', functionName)
let outCalls = scopesToPass.map(x => `out ${x}.`)
let inReturns = scopesToPass.reverse().map(x => `in ${x}.`)

return parallel(
ambient('call',
seq(`${outCalls}in ${functionName}.open_`,
ambient('return', `open_.${inReturns}in func`))),
ambient('func',
seq(`in_ ${functionName}.open ${functionName}.open_`)),
'open func')
}

newScope (name) {
return new Scope(name, this)
}

capabilities () {
return {
toAlgebra: () => {
return this._auths.map((auth) => `out_ ${auth.exit}.in_ ${auth.enter}`).join('|')
}
}
}

allow (exit, enter) {
if (this._parentScope === undefined) {
return []
}
this._auths.push({ exit: exit, enter: enter })
return [this._name].concat(this._parentScope.allow(exit, enter))
}
}

module.exports = {
Scope,
literal,
binaryExpression,
functionExpression,
functionDefinition,
programFile,
callExpression,
parameterDeclaration,
variableExpression,
funcEnvelope

}
31 changes: 31 additions & 0 deletions src/esprima_ast_mapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const esprima = require('esprima')

const astMapper = () => ({
mappers: {},
match: function (nodetype, func) {
this.mappers[nodetype] = func
},
parse: function (node, context) {
if (Array.isArray(node)) {
return node
.map((n) => this.parse(n, context))
.filter(x => x)
.reduce((acc, x) => acc.concat(x), [])
}
let mappingFunc = this.mappers[node.type]
if (mappingFunc === undefined)
return undefined

return mappingFunc(node, context)
},
parseAndMap: function (js) {
let counter = 0
let esprimaMapper = (node, meta) => {
console.log(`${++counter}: ${node.type} (${js.substring(meta.start.offset, meta.end.offset)}) - (${Object.keys(node)})`)
}
return this.parse(esprima.parseScript(js, {}, esprimaMapper))
}
})


module.exports = astMapper
Loading