diff --git a/README.md b/README.md index 420fe960..748a6a59 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ type inference is supported by type checker. - [x] pow as arithmetic operator - [x] variable index expression for vectors - [ ] gentype for function outline - - [ ] functional structs + - [x] functional structs - [ ] destruct - [ ] symbols and enums diff --git a/src/glsl/index.js b/src/glsl/index.js index 9e1052a8..193f2da4 100644 --- a/src/glsl/index.js +++ b/src/glsl/index.js @@ -322,6 +322,7 @@ function handleAlloc(init, typeAnnotation, name) { if (init.type === 'CallExpression') { switch (typeAnnotation) { + // BuiltIn info! case 'int': case 'float': case 'bool': @@ -336,21 +337,29 @@ function handleAlloc(init, typeAnnotation, name) { allocation = ''; } break; - default: - if (init.arguments.length) { + default: { + const [first] = init.arguments; + + if (typeAnnotation === init.callee.name || (first && first.type === 'ArrayExpression')) { if (init.arguments.length === 1) { - const [first] = init.arguments; + if (first.type === 'ArrayExpression') { - const els = first.elements.map((n) => `${handleNode(n)}`).join(', '); + const els = first.elements.map((n) => `${handleNode(n)}`) + .join(', '); allocation = ` = ${typeAnnotation}(${els});`; } else { allocation = ` = ${handleNode(init.arguments[0])}`; } + } else if (!init.arguments.length) { + allocation = ''; } else { throwError(`classes dont support init calls yet ${typeAnnotation}`, init); } + } else { + allocation = ` = ${handleNode(init)};`; } break; + } } } else if (init.type === 'NewExpression') { if (init.arguments.length) { @@ -376,30 +385,10 @@ function handleBody(body, tabCount = 0) { .join('\n'); } -// function replaceGenType(node) { -// console.log('replaceGenType', node); -// return node; -// } -// -// function handleGenTypes(body) { -// return body.map((node) => { -// if (node.right && node.right.init && node.right.init.returnType === 'genType') { -// return [ -// replaceGenType(JSON.parse(JSON.stringify(node)), 'float'), -// replaceGenType(JSON.parse(JSON.stringify(node)), 'vec2'), -// replaceGenType(JSON.parse(JSON.stringify(node)), 'vec3'), -// replaceGenType(JSON.parse(JSON.stringify(node)), 'vec4') -// ]; -// } -// return [node]; -// }).flat(1); -// } - function handeAst(node) { const { body } = node.body[0].expression; body.body = body.body.filter(({ type }) => (type !== 'ReturnStatement')); - // body.body = handleGenTypes(body.body); let sh = handleBody(body); sh = sh.split('\n').map((s) => { @@ -424,24 +413,26 @@ export function buildGLSL(fun, { glsl = true, js = undefined, ast = undefined } let node; let code; let text; + + if (js) { + if (js === true) { + js = {}; + } + if (js) { + code = readOnlyView(sim(fun, { BuiltIn, ...js })); + } + } try { if (glsl || ast) { str = fun.toString(); - node = parse(str, TREE_SETTINGS); + node = parse(str, { ...TREE_SETTINGS }); } if (glsl) { text = handeAst(node); } - if (js) { - if (js === true) { - js = {}; - } - code = sim(fun, { BuiltIn, ...js }); - } - - return { glsl: text, ast: node, js: readOnlyView(code), [ORIGINALS]: [fun] }; + return { glsl: text, ast: node, js: code, [ORIGINALS]: [fun] }; } catch (e) { if (e[LINE]) { const allLines = str.split('\n'); @@ -459,28 +450,39 @@ ${e.message}`); } } -export function joinGLSL(args, { glsl: glslOn = true, js: jsOn = false, ast: astOn = false } = {}) { +export function joinGLSL(args, { glsl: glslOn = true, js = undefined, ast: astOn = false } = {}) { + if (js === true) { + js = {}; + } + if (js) { + js = { BuiltIn, ...js }; + } + const options = { ...TREE_SETTINGS, scope: {} }; - const { asts, js, originals, keys } = args.reduce((mem, { [ORIGINALS]: originals }) => { - if (jsOn) { + const { asts, js: newJs, originals, keys } = args.reduce((mem, { [ORIGINALS]: originals }) => { + + if (js) { originals.forEach((original) => { - mem.js = sim(original, { BuiltIn }, mem.keys); - Object.entries(mem.js).forEach(([key, value]) => { - mem.keys[key] = value; - }); + mem.js = sim(original, mem.js, mem.keys); + + Object.entries(mem.js) + .forEach(([key, value]) => { + mem.keys[key] = value; + }); }); } if (glslOn || astOn) { + const opt = { ...options }; originals.forEach((fun) => { const str = fun.toString(); - const ast = parse(str, options); + const ast = parse(str, opt); mem.asts.push(ast); }); } mem.originals.push(...originals); return mem; - }, { asts: [], js: undefined, keys: {}, originals: [] }); + }, { asts: [], js, keys: {}, originals: [] }); let glsl; if (glslOn) { @@ -511,14 +513,13 @@ export function joinGLSL(args, { glsl: glslOn = true, js: jsOn = false, ast: ast glsl = handeAst({ body: [{ expression: { body: { body } } }] }); } - if (js) { - Object.entries(keys).forEach(([key, value]) => { - if (!js[key]) { - js[key] = value; - } - }); - } - return { glsl, js: readOnlyView(js), [ORIGINALS]: originals }; + Object.entries(keys).forEach(([key, value]) => { + if (!newJs[key]) { + newJs[key] = value; + } + }); + + return { glsl, js: readOnlyView(newJs), [ORIGINALS]: originals }; } export function addErrorHandling(glsl) { diff --git a/src/jstree.js b/src/jstree.js index 4ab6cd2d..4bde3198 100644 --- a/src/jstree.js +++ b/src/jstree.js @@ -59,7 +59,7 @@ function extractFromScope(scope, name, args) { } function extractType(node, target, options) { - const { qualifiers, integer, float, string, boolean, scope, operators } = options; + const { qualifiers, integer, float, string, boolean, scope } = options; const { type, name, callee, arguments: args, value, raw } = node; if (type === 'CallExpression' || type === 'NewExpression') { @@ -136,10 +136,34 @@ function extractType(node, target, options) { const newScope = { ...scope }; target.newInit = handleParams(node, { ...options, scope: newScope }); target.newInit.returnType = 'void'; - } else if (operators && type === 'BinaryExpression') { + } else if (type === 'BinaryExpression') { const left = extractFromScope(scope, node.left.name, []); const right = extractFromScope(scope, node.right.name, []); - target.typeAnnotation = operators(left, node.operator, right); + switch (node.operator) { + case '+': { + target.typeAnnotation = scope.add(left, right); + break; + } + case '-': { + target.typeAnnotation = scope.sub(left, right); + break; + } + case '*': { + target.typeAnnotation = scope.mul(left, right); + break; + } + case '/': { + target.typeAnnotation = scope.div(left, right); + break; + } + case '%': { + target.typeAnnotation = scope.mod(left, right); + break; + } + default: + // do nothing + break; + } target.newInit = node; } else { target.newInit = node; @@ -202,10 +226,10 @@ function handleNode(node, options) { return node; } -export function parse(input, { qualifiers = [], float = 'Number', integer = float, string = 'String', boolean = 'Boolean', locations = false, ranges = false, operators, scope = {}, ...options } = {}) { +export function parse(input, { qualifiers = [], float = 'Number', integer = float, string = 'String', boolean = 'Boolean', locations = false, ranges = false, scope = {}, ...options } = {}) { // TODO: use onToken !!!! const ast = acorn.parse(input, { ...options, locations, ranges, ecmaVersion: 'latest' }); - const node = handleNode(ast, { qualifiers, integer, float, string, boolean, scope, operators }); + const node = handleNode(ast, { qualifiers, integer, float, string, boolean, scope }); return node; } diff --git a/test/glsl/index.js b/test/glsl/index.js index 761437e9..3e5cf3c0 100755 --- a/test/glsl/index.js +++ b/test/glsl/index.js @@ -295,23 +295,6 @@ void fnFVoid() { assert.equal(glsl.trim(), expected.trim()); }); - it('interpret gentype works.', () => { - const { glsl, ast } = buildGLSL(() => { - const foo = gentype((x = gentype()) => { - let res = gentype(x * 5.0); - return res; - }); - }); - - const expected = ` -gentype foo(gentype x) { -\tgentype res = x * 5.0; -\treturn res; -} - `; - assert.equal(glsl.trim(), expected.trim()); - }); - it('works glsl 3.0 in and out.', () => { const { glsl } = buildGLSL(() => { let foo = input(vec2); @@ -447,4 +430,51 @@ int len = int(mat.length()); assert.equal(glsl.trim(), expected.trim()); }); + + it('works fine with joining glsl snippets type inference', () => { + const shader1 = ({ cls, vec2, float }) => { + let Foo = cls({ + bar: vec2, + zahl: float + }); + let prepareBar = Foo((g = float()) => { + let fee = new Foo(); + fee.bar = vec2(g, 2.0); + fee.zahl = 5.0; + return fee; + }); + return { Foo, prepareBar }; + }; + const shader2 = ({ vec2, Foo, prepareBar }) => { + let bar = Foo(() => { + let baz = prepareBar(4.0); + baz.bar = vec2(1.0, 2.0); + baz.zahl = 5.0; + return baz; + }); + return { bar }; + }; + const one = buildGLSL(shader1); + const two = buildGLSL(shader2); + const mixed = joinGLSL([one, two], { glsl: true, js: true /* only for debugging */ }); + const { glsl } = mixed; + + const expected = ` +struct Foo { vec2 bar; float zahl; }; +Foo prepareBar(float g) { +\tFoo fee; +\tfee.bar = vec2(g, 2.0); +\tfee.zahl = 5.0; +\treturn fee; +} +Foo bar() { +\tFoo baz = prepareBar(4.0); +\tbaz.bar = vec2(1.0, 2.0); +\tbaz.zahl = 5.0; +\treturn baz; +} +`; + + assert.equal(glsl.trim(), expected.trim()); + }); }); diff --git a/test/jstree.js b/test/jstree.js index dd2130de..e48ecca1 100755 --- a/test/jstree.js +++ b/test/jstree.js @@ -371,7 +371,6 @@ describe('jstree autodetect primitive tests', () => { assert.equal(init.raw, '+5.0'); }); - it('extract type via autodetect integer', () => { const node = parse('let x = 5;', { integer: 'SPECIAL' }); @@ -503,11 +502,14 @@ describe('jstree autodetect primitive tests', () => { let foo = z * z; let bar = y * foo; return foo; - });`, { operators: (left, operator, right) => { - if (left === 'Mat3' && right === 'Mat3') { - return 'Mat3'; - } if (left === 'Vec2' && right === 'Mat3') { - return 'Vec2'; + });`, { scope: { + + mul: (left, right) => { + if (left === 'Mat3' && right === 'Mat3') { + return 'Mat3'; + } if (left === 'Vec2' && right === 'Mat3') { + return 'Vec2'; + } } } });