Skip to content

Commit

Permalink
feat: allow for functions with no extra arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
kantord committed Oct 19, 2018
1 parent a4632c9 commit 2649463
Show file tree
Hide file tree
Showing 11 changed files with 276 additions and 17 deletions.
190 changes: 190 additions & 0 deletions src/__tests__/__snapshots__/interpreter.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ exports[`interpreter correct target code $ 2`] = `"(function(_) { return (functi

exports[`interpreter correct target code ($x + $foobar | [$, $foobar]) where $x = 3 $foobar = ($x + 1) 1`] = `"(function(_) { return (function(input) { return ((function() {_ = _.assign('x', (3), _); _ = _.assign('foobar', ((_.get('x')+1)), _); return (((function (input) {return [input, _.get('foobar')]})(_.get('x')+_.get('foobar'))))})())})})"`;

exports[`interpreter correct target code ([1, 2] | foo) where $foo = $reverse 1`] = `"(function(_) { return (function(input) { return ((function() {_ = _.assign('foo', (_.get('reverse')), _); return (((function (input) {return _.foo(input)})([1, 2])))})())})})"`;

exports[`interpreter correct target code ([1] | foo 4) where $foo = ($ => $ => 4) 1`] = `"(function(_) { return (function(input) { return ((function() {_ = _.assign('foo', (((function(input) {return (function(input) {return 4})}))), _); return (((function (input) {return _.foo(4)(input)})([1])))})())})})"`;

exports[`interpreter correct target code ([1] | map $foo | $[0]) where $foo = ($ => 4) 1`] = `"(function(_) { return (function(input) { return ((function() {_ = _.assign('foo', (((function(input) {return 4}))), _); return (((function (input) {return (function (input) {return _.projection(input, [0])})(_.map(_.get('foo'))(input))})([1])))})())})})"`;

exports[`interpreter correct target code (3 + $foobar | [$, $foobar]) where $foobar = $ 1`] = `"(function(_) { return (function(input) { return ((function() {_ = _.assign('foobar', (input), _); return (((function (input) {return [input, _.get('foobar')]})(3+_.get('foobar'))))})())})})"`;
Expand Down Expand Up @@ -778,6 +782,192 @@ Object {
}
`;

exports[`interpreter correct target tree ([1, 2] | foo) where $foo = $reverse 1`] = `
Object {
"status": true,
"value": Object {
"end": Object {
"column": 37,
"line": 1,
"offset": 36,
},
"name": "assignment",
"start": Object {
"column": 1,
"line": 1,
"offset": 0,
},
"value": Object {
"assignments": Array [
Array [
Object {
"name": "identifier",
"value": "foo",
},
Object {
"end": Object {
"column": 37,
"line": 1,
"offset": 36,
},
"name": "variable",
"start": Object {
"column": 29,
"line": 1,
"offset": 28,
},
"value": "$reverse",
},
],
],
"program": Object {
"name": "parentheses",
"value": Object {
"name": "pipe",
"value": Object {
"left": Object {
"end": Object {
"column": 8,
"line": 1,
"offset": 7,
},
"name": "list",
"start": Object {
"column": 2,
"line": 1,
"offset": 1,
},
"value": Array [
Object {
"name": "primitive",
"value": "1",
},
Object {
"name": "primitive",
"value": "2",
},
],
},
"right": Object {
"name": "functionCall",
"value": Object {
"left": Object {
"name": "identifier",
"value": "foo",
},
"right": null,
},
},
},
},
},
},
},
}
`;

exports[`interpreter correct target tree ([1] | foo 4) where $foo = ($ => $ => 4) 1`] = `
Object {
"status": true,
"value": Object {
"end": Object {
"column": 41,
"line": 1,
"offset": 40,
},
"name": "assignment",
"start": Object {
"column": 1,
"line": 1,
"offset": 0,
},
"value": Object {
"assignments": Array [
Array [
Object {
"name": "identifier",
"value": "foo",
},
Object {
"name": "parentheses",
"value": Object {
"end": Object {
"column": 40,
"line": 1,
"offset": 39,
},
"name": "lambda",
"start": Object {
"column": 29,
"line": 1,
"offset": 28,
},
"value": Object {
"end": Object {
"column": 40,
"line": 1,
"offset": 39,
},
"name": "lambda",
"start": Object {
"column": 34,
"line": 1,
"offset": 33,
},
"value": Object {
"name": "primitive",
"value": "4",
},
},
},
},
],
],
"program": Object {
"name": "parentheses",
"value": Object {
"name": "pipe",
"value": Object {
"left": Object {
"end": Object {
"column": 5,
"line": 1,
"offset": 4,
},
"name": "list",
"start": Object {
"column": 2,
"line": 1,
"offset": 1,
},
"value": Array [
Object {
"name": "primitive",
"value": "1",
},
],
},
"right": Object {
"name": "functionCall",
"value": Object {
"left": Object {
"name": "identifier",
"value": "foo",
},
"right": Object {
"name": "primitive",
"value": "4",
},
},
},
},
},
},
},
},
}
`;

exports[`interpreter correct target tree ([1] | map $foo | $[0]) where $foo = ($ => 4) 1`] = `
Object {
"status": true,
Expand Down
15 changes: 14 additions & 1 deletion src/__tests__/builtins.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import builtIns from '../builtins'

const { projection, join, map, sortBy, filter, get, assign } = builtIns
const { projection, join, map, sortBy, filter, get, assign, reverse } = builtIns

describe('built ins', () => {
describe('projection', () => {
Expand Down Expand Up @@ -67,6 +67,19 @@ describe('built ins', () => {
})
})

describe('reverse', () => {
it('returns correct value', () => {
expect(reverse(['c', 'a', 'b'])).toEqual(['b', 'a', 'c'])
})

it('does not mutate original array', () => {
const input = ['c', 'a', 'b']
const originalValue = input.slice()
reverse(input)
expect(input).toEqual(originalValue)
})
})

describe('filter', () => {
it('returns correct value', () => {
const foo = a => a.foo >= 0; // eslint-disable-line
Expand Down
8 changes: 8 additions & 0 deletions src/__tests__/interpreter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,14 @@ const tests = [
{
sourceCode: `([1] | map $foo | $[0]) where $foo = ($ => 4)`,
output: 4
},
{
sourceCode: `([1] | foo 4) where $foo = ($ => $ => 4)`,
output: 4
},
{
sourceCode: `([1, 2] | foo) where $foo = $reverse`,
output: [2, 1]
}
]

Expand Down
7 changes: 4 additions & 3 deletions src/builtins.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ export default {
input: Array<mixed>
): Array<mixed> => input.filter(f),
get: function (variable: string): mixed {
return this[`__var__${variable}`]
return this[variable]
},
assign: function (
variable: string,
value: mixed,
context: {[string]: mixed}
): {[string]: mixed} {
return Object.assign({}, context, { [`__var__${variable}`]: value })
}
return Object.assign({}, context, { [variable]: value })
},
reverse: (input: Array<mixed>): Array<mixed> => input.slice().reverse()
}
22 changes: 19 additions & 3 deletions src/generators/__tests__/functionCall.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import functionCall from '../functionCall'

const fakeGenerator = (
{ name } // eslint-disable-line flowtype/require-parameter-type
): string => '[]'

describe('functionCall generator', () => {
it('generates correct code', () => {
const fakeGenerator = (
{ name } // eslint-disable-line flowtype/require-parameter-type
): string => '[]'
expect(
functionCall(fakeGenerator)({
name: 'functionCall',
Expand All @@ -23,4 +24,19 @@ describe('functionCall generator', () => {
})
).toEqual('_.foo([])(input)')
})

it('generates correct code - no args', () => {
expect(
functionCall(fakeGenerator)({
name: 'functionCall',
value: {
left: {
name: 'identifier',
value: 'foo'
},
right: null
}
})
).toEqual('_.foo(input)')
})
})
4 changes: 3 additions & 1 deletion src/generators/functionCall.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ export default (
): (FunctionCallNodeType => GeneratedCodeType) => ({
value
}: FunctionCallNodeType): GeneratedCodeType =>
`_.${value.left.value}(${Generator(value.right)})(input)`
value.right
? `_.${value.left.value}(${Generator(value.right)})(input)`
: `_.${value.left.value}(input)`
17 changes: 17 additions & 0 deletions src/parsers/__tests__/functionCall.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ describe('functionCall parser', () => {
expect(parser.parse('join ", "').status).toBe(true)
})

it('parses replace', () => {
expect(parser.parse('replace').status).toBe(true)
})

it('returns correct value', () => {
expect(parser.parse('replace ", ": "; "').value).toEqual({
name: 'functionCall',
Expand All @@ -29,4 +33,17 @@ describe('functionCall parser', () => {
}
})
})

it('returns correct value', () => {
expect(parser.parse('reverse').value).toEqual({
name: 'functionCall',
value: {
left: {
name: 'identifier',
value: 'reverse'
},
right: null
}
})
})
})
12 changes: 12 additions & 0 deletions src/parsers/__tests__/identifier.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ describe('identifier parser', () => {
it('parses foobar_123', () => {
expect(parser.parse('foobar_123').status).toBe(true)
})
it('parses false_', () => {
expect(parser.parse('false_').status).toBe(true)
})
it('returns correct value', () => {
expect(parser.parse('foobar_123').value).toEqual({
name: 'identifier',
Expand All @@ -19,4 +22,13 @@ describe('identifier parser', () => {
it('does not parse 0foo', () => {
expect(parser.parse('0foo').status).toBe(false)
})
it('does not parse false', () => {
expect(parser.parse('false').status).toBe(false)
})
it('does not parse true', () => {
expect(parser.parse('true').status).toBe(false)
})
it('does not parse null', () => {
expect(parser.parse('null').status).toBe(false)
})
})
4 changes: 2 additions & 2 deletions src/parsers/functionCall.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {
const FunctionCallParser = P.lazy((): mixed => {
const TupleParser = require('./tuple/tuple').default
const IdentifierParser = require('./identifier').default
return P.seq(IdentifierParser, crap, TupleParser).map(
return P.seq(IdentifierParser, crap, TupleParser.atMost(1)).map(
([left, _, right]: [
IdentifierNodeType,
mixed,
Expand All @@ -21,7 +21,7 @@ const FunctionCallParser = P.lazy((): mixed => {
name: 'functionCall',
value: {
left,
right
right: right[0] || null
}
})
)
Expand Down
12 changes: 6 additions & 6 deletions src/parsers/identifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import P from 'parsimmon'
import type { IdentifierNodeType } from '../types'

export default P.regexp(/[a-zA-Z][0-9a-zA-Z_$]*/).map(
(value: string): IdentifierNodeType => ({
name: 'identifier',
value
})
)
export default P.regexp(
/((?!null|false|true)[a-zA-Z][0-9a-zA-Z_$]*|(null|false|true)[0-9a-zA-Z_$])/
).map((value: string): IdentifierNodeType => ({
name: 'identifier',
value
}))
Loading

0 comments on commit 2649463

Please sign in to comment.