🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more →
Sign In

flang

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

flang - npm Package Compare versions

Comparing version
0.0.1
to
0.0.2
+143
-15
lib/core.js

@@ -51,3 +51,3 @@ 'use strict'

}
return isIdentifier(true) || /^[0-9-]$/.test(char)
return isIdentifier(true) || /^[0-9-]$/.test(char) || char === '.'
}

@@ -62,2 +62,5 @@

.find(s => s.startsWith(start + peek()))
if (start[0] === '/' && isIdentifier()) {
throw new Error('Unexpected internal call')
}
return Boolean(starters)

@@ -69,3 +72,3 @@ }

while (peek() !== '') {
while (whitespace.includes(peek())) next()
while (peek() && whitespace.includes(peek())) next()

@@ -149,2 +152,10 @@ if (peek() === '') break

return sExpr
} else if (peek() === '[') {
next()
const list = ['/list']
while (peek() !== '' && peek() !== ']') {
list.push(parseExpression())
}
next()
return list
} else if (/^[a-zA-Z$_-]+$/.test(peek())) {

@@ -184,3 +195,5 @@ return next()

const unaryOps = []
const unaryOps = [
['/str', x => x]
]

@@ -193,8 +206,105 @@ const nativeGlobals = Object.fromEntries([

const evaluate = exports.evaluate = (expression) => {
class Scope {
constructor (parent) {
this.parent = parent
this.variables = new Map()
}
lookup (name) {
if (this.variables.has(name)) return this.variables.get(name)
if (this.parent) return this.parent.lookup(name)
throw new Error('Unknown variable ' + name)
}
}
class Fn {
constructor (name, argList, body, parentScope) {
this.name = name
this.argList = argList
this.body = body
this.parentScope = parentScope
Object.freeze(this)
}
}
const toArgList = argList => {
if (argList[0] !== '/list') {
throw new Error('function was not given a list as the argument list')
}
argList.shift()
if (!argList.every(x => typeof x === 'string')) {
throw new Error('non-name argument in argument list')
}
return argList
}
const compile = exports.compile = (expression) => {
if (typeof expression === 'string') return expression
if (typeof expression === 'number') return expression
if (typeof expression === 'boolean') return expression
let [head, ...args] = expression
if (Array.isArray(head)) {
return `(${compile(head)})(${args.map(compile).join(', ')})`
}
if (head === 'do') {
if (!args.length) return 'null'
args = args.map(compile)
if (args.length === 1) return args[0]
const last = args.pop()
return '(()=>{' + args.join(';') + ';return ' + last + '})()'
} else if (head === 'if') {
args = args.map(compile)
if (args.length < 3) args.push('null')
return `(${args[0]}?${args[1]}:${args[2]})`
} else if (head === 'def') {
return `let ${args[0]}=${compile(args[1])}`
} else if (head === 'set') {
return `(${args[0]}=${compile(args[1])})`
} else if (head === 'fn') {
const name = args[0][0] === '/list' ? '' : args.shift()
const argList = args.shift().slice(1).join(',')
const body = compile(['do', ...args])
if (name) {
return `(function ${name}(${argList}){return ${body}})`
}
return `((${argList}) => ${body})`
} else if (head === '/str') {
return JSON.stringify(args[0])
} else if (head === '/list') {
return JSON.stringify(args)
} else if (comparisonOperators.includes(head)) {
return `(${args.map(compile).reduce((a, b) => `(${a})${head}${b}`)})`
} else if (binaryOperators.includes(head)) {
return '(' + args.map(compile).join(head) + ')'
} else if (typeof head === 'string') {
return `${head}(${args.map(compile).join(',')})`
}
throw new Error('unknown expression ' + head)
}
const evaluate = exports.evaluate = (expression, stack = [new Scope(null)]) => {
const scope = stack[stack.length - 1]
if (typeof expression === 'string') {
return scope.lookup(expression)
}
const isAtom = !Array.isArray(expression)
const push = (s = new Scope(scope)) => stack.concat(s)
if (isAtom) {
return expression
}
const [head, ...args] = expression
let [head, ...args] = expression
if (Array.isArray(head)) {
head = evaluate(head, stack)
}
if (head instanceof Fn) {
const fnScope = new Scope(head.parentScope)
head.argList.forEach((arg, i) => {
fnScope.variables.set(arg, evaluate(args[i], stack))
})
return evaluate(head.body, push(fnScope))
}
if (head in nativeGlobals) {

@@ -205,15 +315,34 @@ const func = nativeGlobals[head]

if (head === 'do') {
for (var i = 0; ; i++) {
const isLast = i === args.length - 1
const val = evaluate(args[i])
if (isLast) return val
let val
const doStack = push()
for (let i = 0; i < args.length; i++) {
val = evaluate(args[i], doStack)
}
return val
} else if (head === 'if') {
const [cond, then, alternate] = args
if (evaluate(cond)) {
return evaluate(then)
if (evaluate(cond, stack)) {
return evaluate(then, stack)
} else if (alternate != null) {
return evaluate(alternate)
return evaluate(alternate, stack)
}
return null
} else if (head === 'fn') {
let name
if (!Array.isArray(args[0])) {
name = args.shift()
}
if (!Array.isArray(args[0])) {
throw new Error('function without arguments list')
}
const argList = toArgList(args.shift())
return new Fn(name, argList, ['do', ...args], scope)
} else if (head === 'set') {
const value = evaluate(args[1], scope)
scope.variables.set(args[0], value)
return value
} else if (head === 'def') {
const value = evaluate(args[1], scope)
scope.variables.set(args[0], value)
return value
} else {

@@ -224,4 +353,3 @@ throw new Error('Unknown function or macro ' + head)

exports.parseEvaluate = (source) => {
return evaluate(exports.parse(source))
}
exports.parseEvaluate = source => evaluate(exports.parse(source))
exports.parseCompile = source => compile(exports.parse(source))
+6
-2
{
"name": "flang",
"version": "0.0.1",
"version": "0.0.2",
"description": "",

@@ -17,3 +17,3 @@ "main": "lib/index.js",

"scripts": {
"test": "mocha",
"test": "mocha -r ./register.js test/*.js test/*.fl",
"lint": "eslint --fix 'lib/**/*.js'"

@@ -31,2 +31,3 @@ },

"eslint-plugin-standard": "^4.0.0",
"flang": "0.0.1",
"husky": "^3.0.3",

@@ -49,3 +50,6 @@ "mocha": "^6.2.0"

}
},
"dependencies": {
"pirates": "^4.0.1"
}
}