glre 0.33.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -98
- package/dist/index.cjs +29 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1813 -248
- package/dist/index.js +29 -31
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +29 -31
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.ts +15 -13
- package/dist/native.js +29 -31
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +29 -31
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +29 -31
- package/dist/react.js.map +1 -1
- package/dist/solid.cjs +29 -31
- package/dist/solid.cjs.map +1 -1
- package/dist/solid.d.ts +1 -1
- package/dist/solid.js +29 -31
- package/dist/solid.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +10 -2
- package/src/node/code.ts +13 -9
- package/src/node/const.ts +57 -30
- package/src/node/index.ts +111 -98
- package/src/node/infer.ts +47 -64
- package/src/node/node.ts +19 -17
- package/src/node/parse.ts +38 -33
- package/src/node/scope.ts +25 -20
- package/src/node/types.ts +222 -98
- package/src/node/utils.ts +6 -6
- package/src/types.ts +13 -11
- package/src/utils/program.ts +10 -11
- package/src/webgl.ts +17 -8
- package/src/webgpu.ts +11 -7
package/src/node/infer.ts
CHANGED
|
@@ -1,108 +1,91 @@
|
|
|
1
1
|
import { is } from '../utils/helpers'
|
|
2
2
|
import {
|
|
3
|
-
BOOL_RETURN_FUNCTIONS,
|
|
4
3
|
BUILTIN_TYPES,
|
|
5
4
|
COMPARISON_OPERATORS,
|
|
6
5
|
COMPONENT_COUNT_TO_TYPE,
|
|
7
|
-
|
|
8
|
-
FIRST_ARG_TYPE_FUNCTIONS,
|
|
9
|
-
HIGHEST_TYPE_FUNCTIONS,
|
|
6
|
+
FUNCTION_RETURN_TYPES,
|
|
10
7
|
LOGICAL_OPERATORS,
|
|
11
|
-
PRESERVE_TYPE_FUNCTIONS,
|
|
12
|
-
SCALAR_RETURN_FUNCTIONS,
|
|
13
|
-
VEC3_RETURN_FUNCTIONS,
|
|
14
|
-
VEC4_RETURN_FUNCTIONS,
|
|
15
8
|
} from './const'
|
|
16
9
|
import { isConstants, isNodeProxy, isSwizzle } from './utils'
|
|
17
|
-
import type { Constants, NodeContext, NodeProxy, X } from './types'
|
|
10
|
+
import type { Constants as C, NodeContext, NodeProxy, X } from './types'
|
|
18
11
|
|
|
19
|
-
const
|
|
20
|
-
return
|
|
21
|
-
const currentType = infer(current, c)
|
|
22
|
-
const highestPriority = CONSTANTS.indexOf(highest as any)
|
|
23
|
-
const currentPriority = CONSTANTS.indexOf(currentType as any)
|
|
24
|
-
return currentPriority > highestPriority ? currentType : highest
|
|
25
|
-
}, 'float') as Constants
|
|
12
|
+
const inferBuiltin = <T extends C>(id: string | undefined) => {
|
|
13
|
+
return BUILTIN_TYPES[id as keyof typeof BUILTIN_TYPES] as T
|
|
26
14
|
}
|
|
27
15
|
|
|
28
|
-
|
|
29
|
-
|
|
16
|
+
// Unified logic with types.ts InferOperator type
|
|
17
|
+
const inferOperator = <T extends C>(L: T, R: T, op: string): T => {
|
|
18
|
+
if (COMPARISON_OPERATORS.includes(op as any) || LOGICAL_OPERATORS.includes(op as any)) return 'bool' as T
|
|
19
|
+
if (L === R) return L
|
|
20
|
+
// broadcast
|
|
21
|
+
if (L === 'float' || L === 'int') return R
|
|
22
|
+
if (R === 'float' || R === 'int') return L
|
|
23
|
+
// mat * vec → vec
|
|
24
|
+
if (L === 'mat4' && R === 'vec4') return R
|
|
25
|
+
if (L === 'mat3' && R === 'vec3') return R
|
|
26
|
+
if (L === 'mat2' && R === 'vec2') return R
|
|
27
|
+
// vec * mat → vec
|
|
28
|
+
if (L === 'vec4' && R === 'mat4') return L
|
|
29
|
+
if (L === 'vec3' && R === 'mat3') return L
|
|
30
|
+
if (L === 'vec2' && R === 'mat2') return L
|
|
31
|
+
return L
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
if (
|
|
35
|
-
if (
|
|
36
|
-
if (
|
|
37
|
-
|
|
38
|
-
if (VEC3_RETURN_FUNCTIONS.includes(funcName as any)) return 'vec3'
|
|
39
|
-
if (VEC4_RETURN_FUNCTIONS.includes(funcName as any)) return 'vec4'
|
|
40
|
-
if (HIGHEST_TYPE_FUNCTIONS.includes(funcName as any)) return getHighestPriorityType(args, c)
|
|
41
|
-
return firstArgType
|
|
34
|
+
export const inferPrimitiveType = <T extends C>(x: X) => {
|
|
35
|
+
if (is.bol(x)) return 'bool' as T
|
|
36
|
+
if (is.str(x)) return 'texture' as T
|
|
37
|
+
if (is.num(x)) return 'float' as T // @TODO FIX: Number.isInteger(x) ? 'int' : 'float'
|
|
38
|
+
if (is.arr(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] as T
|
|
39
|
+
return 'float' as T
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
if (LOGICAL_OPERATORS.includes(op as any)) return 'bool'
|
|
47
|
-
if (leftType === rightType) return leftType as Constants
|
|
48
|
-
if (leftType.includes('vec') && !rightType.includes('vec')) return leftType as Constants
|
|
49
|
-
if (rightType.includes('vec') && !leftType.includes('vec')) return rightType as Constants
|
|
50
|
-
const leftPriority = CONSTANTS.indexOf(leftType as any)
|
|
51
|
-
const rightPriority = CONSTANTS.indexOf(rightType as any)
|
|
52
|
-
return (leftPriority >= rightPriority ? leftType : rightType) as Constants
|
|
42
|
+
const inferFromCount = <T extends C>(count: number) => {
|
|
43
|
+
return COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE] as T
|
|
53
44
|
}
|
|
54
45
|
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
if (is.str(x)) return 'texture'
|
|
58
|
-
if (is.num(x)) return Number.isInteger(x) ? 'int' : 'float'
|
|
59
|
-
if (is.arr(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] || 'float'
|
|
60
|
-
return 'float'
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const inferFromCount = (count: number): Constants => {
|
|
64
|
-
return COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE]!
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const inferFromArray = (arr: X[], c: NodeContext): Constants => {
|
|
68
|
-
if (arr.length === 0) return 'void'
|
|
46
|
+
const inferFromArray = <T extends C>(arr: X<T>[], c: NodeContext) => {
|
|
47
|
+
if (arr.length === 0) return 'void' as T
|
|
69
48
|
const [x] = arr
|
|
70
|
-
if (is.str(x)) return x as
|
|
49
|
+
if (is.str(x)) return x as T // for struct
|
|
71
50
|
const ret = infer(x, c)
|
|
72
51
|
for (const x of arr.slice(1))
|
|
73
52
|
if (ret !== infer(x, c)) throw new Error(`glre node system error: defined scope return mismatch`)
|
|
74
53
|
return ret
|
|
75
54
|
}
|
|
76
55
|
|
|
77
|
-
export const
|
|
56
|
+
export const inferFunction = <T extends C>(x: X) => {
|
|
57
|
+
return FUNCTION_RETURN_TYPES[x as keyof typeof FUNCTION_RETURN_TYPES] as T
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const inferImpl = <T extends C>(target: NodeProxy<T>, c: NodeContext): T => {
|
|
78
61
|
const { type, props } = target
|
|
79
|
-
const { id, children = [],
|
|
62
|
+
const { id, children = [], inferFrom, layout } = props
|
|
80
63
|
const [x, y, z] = children
|
|
81
|
-
if (type === 'conversion') return x
|
|
82
|
-
if (type === 'operator') return inferOperator(infer(y, c), infer(z, c), x
|
|
83
|
-
if (type === 'function') return inferFunction(x as string, children.slice(1), c)
|
|
64
|
+
if (type === 'conversion') return x
|
|
65
|
+
if (type === 'operator') return inferOperator(infer(y, c), infer(z, c), x)
|
|
84
66
|
if (type === 'ternary') return inferOperator(infer(y, c), infer(z, c), 'add')
|
|
85
67
|
if (type === 'builtin') return inferBuiltin(id)
|
|
86
|
-
if (type === '
|
|
68
|
+
if (type === 'function') return inferFunction(x) || infer(y, c)
|
|
69
|
+
if (type === 'define' && isConstants(layout?.type)) return layout?.type as T
|
|
87
70
|
if (type === 'attribute' && is.arr(x) && c.gl?.count) return inferFromCount(x.length / c.gl.count)
|
|
88
71
|
if (type === 'member') {
|
|
89
72
|
if (isSwizzle(x)) return inferFromCount(x.length)
|
|
90
73
|
if (isNodeProxy(y) && is.str(x)) {
|
|
91
|
-
const field = y.props.fields?.[x] // for variable node of struct member
|
|
74
|
+
const field = (y as any).props.fields?.[x] // for variable node of struct member
|
|
92
75
|
if (field) return infer(field, c)
|
|
93
76
|
}
|
|
94
|
-
return 'float' // fallback @TODO FIX
|
|
77
|
+
return 'float' as T // fallback @TODO FIX
|
|
95
78
|
}
|
|
96
79
|
if (inferFrom) return inferFromArray(inferFrom, c)
|
|
97
|
-
return infer(x, c)
|
|
80
|
+
return infer(x, c) // for uniform
|
|
98
81
|
}
|
|
99
82
|
|
|
100
|
-
export const infer = (target: X
|
|
83
|
+
export const infer = <T extends C>(target: X<T>, c?: NodeContext | null): T => {
|
|
101
84
|
if (!c) c = {}
|
|
102
85
|
if (!isNodeProxy(target)) return inferPrimitiveType(target)
|
|
103
86
|
if (is.arr(target)) return inferFromCount(target.length)
|
|
104
|
-
if (!c.infers) c.infers = new WeakMap<NodeProxy
|
|
105
|
-
if (c.infers.has(target)) return c.infers.get(target)
|
|
87
|
+
if (!c.infers) c.infers = new WeakMap<NodeProxy<T>, C>()
|
|
88
|
+
if (c.infers.has(target)) return c.infers.get(target) as T
|
|
106
89
|
const ret = inferImpl(target, c)
|
|
107
90
|
c.infers.set(target, ret)
|
|
108
91
|
return ret
|
package/src/node/node.ts
CHANGED
|
@@ -2,13 +2,13 @@ import { is } from '../utils/helpers'
|
|
|
2
2
|
import { code } from './code'
|
|
3
3
|
import { assign, toVar } from './scope'
|
|
4
4
|
import { conversionToConstant, isConversion, isFunction, isOperator, getId } from './utils'
|
|
5
|
-
import type { Functions, NodeProps, NodeProxy, NodeTypes, Operators, X } from './types'
|
|
5
|
+
import type { Functions, NodeProps, NodeProxy, NodeTypes, Operators, X, Constants as C } from './types'
|
|
6
6
|
|
|
7
7
|
const toPrimitive = (x: X, hint: string) => {
|
|
8
8
|
if (hint === 'string') return code(x)
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export const node = (type: NodeTypes, props?: NodeProps | null, ...args: X[]) => {
|
|
11
|
+
export const node = <T extends C>(type: NodeTypes, props?: NodeProps | null, ...args: X[]) => {
|
|
12
12
|
if (!props) props = {}
|
|
13
13
|
if (args.length) props.children = args
|
|
14
14
|
const listeners = new Set<(value: any) => void>()
|
|
@@ -24,28 +24,30 @@ export const node = (type: NodeTypes, props?: NodeProps | null, ...args: X[]) =>
|
|
|
24
24
|
if (isOperator(key)) return (...y: X[]) => operator(key, x, ...y)
|
|
25
25
|
if (isFunction(key)) return (...y: X[]) => function_(key, x, ...y)
|
|
26
26
|
if (isConversion(key)) return () => conversion(conversionToConstant(key), x)
|
|
27
|
-
if (is.str(key)) return member(key, x) // for struct
|
|
27
|
+
if (is.str(key)) return member(key, x) // for struct and swizzling
|
|
28
28
|
}
|
|
29
29
|
const set = (_: unknown, key: string, y: X) => {
|
|
30
30
|
if (key === 'value') listeners.forEach((fun) => fun(y))
|
|
31
31
|
if (is.str(key)) member(key, x).assign(y)
|
|
32
32
|
return true
|
|
33
33
|
}
|
|
34
|
-
const x = new Proxy({}, { get, set }) as unknown as NodeProxy
|
|
34
|
+
const x = new Proxy({}, { get, set }) as unknown as NodeProxy<T>
|
|
35
35
|
return x
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
// headers
|
|
39
|
-
export const attribute = (x: X, id = getId()) => node('attribute', { id }, x)
|
|
40
|
-
export const constant = (x: X
|
|
41
|
-
export const uniform = (x: X
|
|
42
|
-
export const variable = (id = getId()) => node('variable', { id })
|
|
43
|
-
export const builtin = (id = getId()) => node('builtin', { id })
|
|
44
|
-
export const vertexStage = (x: X
|
|
38
|
+
// headers with proper type inference
|
|
39
|
+
export const attribute = <T extends C>(x: X, id = getId()) => node<T>('attribute', { id }, x)
|
|
40
|
+
export const constant = <T extends C>(x: X<T>, id = getId()) => node<T>('constant', { id }, x)
|
|
41
|
+
export const uniform = <T extends C>(x: X<T>, id = getId()) => node<T>('uniform', { id }, x)
|
|
42
|
+
export const variable = <T extends C>(id = getId()) => node<T>('variable', { id })
|
|
43
|
+
export const builtin = <T extends C>(id = getId()) => node<T>('builtin', { id })
|
|
44
|
+
export const vertexStage = <T extends C>(x: X<T>, id = getId()) => {
|
|
45
|
+
return node<T>('varying', { id, inferFrom: [x] }, x)
|
|
46
|
+
}
|
|
45
47
|
|
|
46
|
-
// Node shorthands
|
|
47
|
-
export const
|
|
48
|
-
export const
|
|
49
|
-
export const
|
|
50
|
-
export const
|
|
51
|
-
export const
|
|
48
|
+
// Node shorthands with proper typing
|
|
49
|
+
export const member = <T extends C>(key: string, x: X) => node<T>('member', null, key, x)
|
|
50
|
+
export const select = <T extends C>(x: X<T>, y: X<T>, z: X) => node<T>('ternary', null, x, y, z) // z ? x : y @TODO REMOVE
|
|
51
|
+
export const operator = <T extends C>(key: Operators, ...x: X[]) => node<T>('operator', null, key, ...x)
|
|
52
|
+
export const function_ = <T extends C>(key: Functions, ...x: X[]) => node<T>('function', null, key, ...x)
|
|
53
|
+
export const conversion = <T extends C>(key: T, ...x: X[]) => node<T>('conversion', null, key, ...x)
|
package/src/node/parse.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { is } from '../utils/helpers'
|
|
2
2
|
import { code } from './code'
|
|
3
3
|
import { infer } from './infer'
|
|
4
|
-
import { formatConversions,
|
|
4
|
+
import { formatConversions, addDependency } from './utils'
|
|
5
5
|
import type { Constants, NodeContext, NodeProps, NodeProxy, X } from './types'
|
|
6
6
|
|
|
7
7
|
export const parseArray = (children: X[], c: NodeContext) => {
|
|
@@ -58,37 +58,6 @@ export const parseDeclare = (c: NodeContext, x: X, y: X) => {
|
|
|
58
58
|
return `var ${varName}: ${wgslType} = ${code(x, c)};`
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Constants | string) => {
|
|
62
|
-
const { id, children = [], layout } = props
|
|
63
|
-
const [x, ...args] = children
|
|
64
|
-
const argParams: [name: string, type: string][] = []
|
|
65
|
-
const params: string[] = []
|
|
66
|
-
if (layout?.inputs)
|
|
67
|
-
for (const input of layout.inputs) {
|
|
68
|
-
argParams.push([input.name, input.type])
|
|
69
|
-
}
|
|
70
|
-
else
|
|
71
|
-
for (let i = 0; i < args.length; i++) {
|
|
72
|
-
argParams.push([`p${i}`, infer(args[i], c)])
|
|
73
|
-
}
|
|
74
|
-
const ret = []
|
|
75
|
-
if (c?.isWebGL) {
|
|
76
|
-
for (const [paramId, type] of argParams) {
|
|
77
|
-
addDependency(c, id!, type)
|
|
78
|
-
params.push(`${type} ${paramId}`)
|
|
79
|
-
}
|
|
80
|
-
addDependency(c, id!, returnType)
|
|
81
|
-
ret.push(`${returnType} ${id}(${params}) {`)
|
|
82
|
-
} else {
|
|
83
|
-
for (const [paramId, type] of argParams) params.push(`${paramId}: ${formatConversions(type, c)}`)
|
|
84
|
-
ret.push(`fn ${id}(${params}) -> ${formatConversions(returnType, c)} {`)
|
|
85
|
-
}
|
|
86
|
-
const scopeCode = code(x, c)
|
|
87
|
-
if (scopeCode) ret.push(scopeCode)
|
|
88
|
-
ret.push('}')
|
|
89
|
-
return ret.join('\n')
|
|
90
|
-
}
|
|
91
|
-
|
|
92
61
|
export const parseStructHead = (c: NodeContext, id: string, fields: Record<string, NodeProxy> = {}) => {
|
|
93
62
|
const lines: string[] = []
|
|
94
63
|
for (const key in fields) {
|
|
@@ -123,11 +92,47 @@ export const parseStruct = (
|
|
|
123
92
|
}
|
|
124
93
|
}
|
|
125
94
|
|
|
95
|
+
/**
|
|
96
|
+
* define
|
|
97
|
+
*/
|
|
98
|
+
export const parseDefine = (c: NodeContext, props: NodeProps, returnType: Constants) => {
|
|
99
|
+
const { id, children = [], layout } = props
|
|
100
|
+
const [x, ...args] = children
|
|
101
|
+
const argParams: [name: string, type: string][] = []
|
|
102
|
+
const params: string[] = []
|
|
103
|
+
if (layout?.inputs)
|
|
104
|
+
for (const input of layout.inputs) {
|
|
105
|
+
argParams.push([input.name, input.type])
|
|
106
|
+
}
|
|
107
|
+
else
|
|
108
|
+
for (let i = 0; i < args.length; i++) {
|
|
109
|
+
argParams.push([`p${i}`, infer(args[i], c)])
|
|
110
|
+
}
|
|
111
|
+
const ret = []
|
|
112
|
+
if (c?.isWebGL) {
|
|
113
|
+
for (const [paramId, type] of argParams) {
|
|
114
|
+
addDependency(c, id!, type)
|
|
115
|
+
params.push(`${type} ${paramId}`)
|
|
116
|
+
}
|
|
117
|
+
addDependency(c, id!, returnType)
|
|
118
|
+
ret.push(`${returnType} ${id}(${params}) {`)
|
|
119
|
+
} else {
|
|
120
|
+
for (const [paramId, type] of argParams) params.push(`${paramId}: ${formatConversions(type, c)}`)
|
|
121
|
+
ret.push(`fn ${id}(${params}) -> ${formatConversions(returnType, c)} {`)
|
|
122
|
+
}
|
|
123
|
+
const scopeCode = code(x, c)
|
|
124
|
+
if (scopeCode) ret.push(scopeCode)
|
|
125
|
+
ret.push('}')
|
|
126
|
+
return ret.join('\n')
|
|
127
|
+
}
|
|
128
|
+
|
|
126
129
|
/**
|
|
127
130
|
* headers
|
|
128
131
|
*/
|
|
129
132
|
export const parseVaryingHead = (c: NodeContext, id: string, type: string) => {
|
|
130
|
-
return c.isWebGL
|
|
133
|
+
return c.isWebGL
|
|
134
|
+
? `${type} ${id};`
|
|
135
|
+
: `@location(${c.code?.vertVaryings?.size || 0}) ${id}: ${formatConversions(type, c)}`
|
|
131
136
|
}
|
|
132
137
|
|
|
133
138
|
export const parseUniformHead = (c: NodeContext, id: string, type: Constants) => {
|
package/src/node/scope.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { int } from '.'
|
|
2
1
|
import { conversion, node } from './node'
|
|
3
2
|
import { getId } from './utils'
|
|
4
|
-
import type { FnLayout, NodeProps, NodeProxy, X } from './types'
|
|
3
|
+
import type { FnLayout, NodeProps, NodeProxy, X, Constants, Int } from './types'
|
|
5
4
|
|
|
6
5
|
let scope: NodeProxy | null = null
|
|
7
6
|
let define: NodeProxy | null = null
|
|
@@ -16,29 +15,28 @@ const addToScope = (x: NodeProxy) => {
|
|
|
16
15
|
props.inferFrom.push(x)
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
export const toVar = (x: X
|
|
18
|
+
export const toVar = <T extends Constants>(x: X<T>, id?: string): NodeProxy<T> => {
|
|
20
19
|
if (!id) id = getId()
|
|
21
|
-
const y = node('variable', { id, inferFrom: [x] })
|
|
20
|
+
const y = node<T>('variable', { id, inferFrom: [x] })
|
|
22
21
|
const z = node('declare', null, x, y)
|
|
23
22
|
addToScope(z)
|
|
24
23
|
return y
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
export const assign = (x: X
|
|
26
|
+
export const assign = <T extends Constants>(x: X<T>, y: X<T>): X<T> => {
|
|
28
27
|
const z = node('assign', null, x, y)
|
|
29
28
|
addToScope(z)
|
|
30
29
|
return x
|
|
31
30
|
}
|
|
32
31
|
|
|
33
|
-
export const Return = (x: X) => {
|
|
34
|
-
const y = node('return', { inferFrom: [x] }, x)
|
|
32
|
+
export const Return = <T extends Constants>(x: X<T>): NodeProxy<T> => {
|
|
33
|
+
const y = node<T>('return', { inferFrom: [x] }, x)
|
|
35
34
|
addToScope(y)
|
|
36
35
|
return y
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return (initialValues: Record<string, NodeProxy> = {}, instanceId = getId()) => {
|
|
38
|
+
export const struct = <T extends Record<string, NodeProxy>>(fields: T, id = getId()) => {
|
|
39
|
+
return (initialValues: T = {} as T, instanceId = getId()) => {
|
|
42
40
|
const x = node('variable', { id: instanceId, inferFrom: [id] })
|
|
43
41
|
const y = node('struct', { id, fields, initialValues }, x)
|
|
44
42
|
addToScope(y)
|
|
@@ -61,7 +59,7 @@ const scoped = (x: NodeProxy, fun: () => NodeProxy | void, y = define) => {
|
|
|
61
59
|
define = _define
|
|
62
60
|
}
|
|
63
61
|
|
|
64
|
-
export const If = (x:
|
|
62
|
+
export const If = (x: NodeProxy, fun: () => void) => {
|
|
65
63
|
const y = node('scope')
|
|
66
64
|
scoped(y, fun)
|
|
67
65
|
const ifNode = node('if', null, x, y)
|
|
@@ -82,15 +80,16 @@ export const If = (x: X, fun: () => void) => {
|
|
|
82
80
|
return ret()
|
|
83
81
|
}
|
|
84
82
|
|
|
85
|
-
export const Loop = (x:
|
|
83
|
+
export const Loop = (x: NodeProxy, fun: (params: { i: Int }) => void) => {
|
|
86
84
|
const y = node('scope')
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
const id = getId()
|
|
86
|
+
scoped(y, () => fun({ i: node<'int'>('variable', { id, inferFrom: [conversion('int', 0)] }) }))
|
|
87
|
+
const ret = node('loop', { id }, x, y)
|
|
89
88
|
addToScope(ret)
|
|
90
89
|
return ret
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
export const Switch = (x:
|
|
92
|
+
export const Switch = (x: NodeProxy) => {
|
|
94
93
|
const switchNode = node('switch', null, x)
|
|
95
94
|
addToScope(switchNode)
|
|
96
95
|
const ret = () => ({
|
|
@@ -111,10 +110,13 @@ export const Switch = (x: X) => {
|
|
|
111
110
|
return ret()
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
export const Fn =
|
|
113
|
+
export const Fn = <ReturnType extends Constants, Args extends Constants[]>(
|
|
114
|
+
fun: (paramVars: NodeProxy[]) => NodeProxy<ReturnType> | void,
|
|
115
|
+
defaultId = getId()
|
|
116
|
+
) => {
|
|
115
117
|
let layout: FnLayout
|
|
116
|
-
const ret = (...args: X[]) => {
|
|
117
|
-
const id = layout?.name ||
|
|
118
|
+
const ret = (...args: X<Args[number]>[]): NodeProxy<ReturnType> => {
|
|
119
|
+
const id = layout?.name || defaultId
|
|
118
120
|
const x = node('scope')
|
|
119
121
|
const paramVars: NodeProxy[] = []
|
|
120
122
|
const paramDefs: NodeProps[] = []
|
|
@@ -127,10 +129,13 @@ export const Fn = (fun: (paramVars: NodeProxy[]) => NodeProxy) => {
|
|
|
127
129
|
paramDefs.push({ id: `p${i}`, inferFrom: [args[i]] })
|
|
128
130
|
}
|
|
129
131
|
for (const props of paramDefs) paramVars.push(node('variable', props))
|
|
130
|
-
const y = node('define', { id, layout }, x, ...args)
|
|
132
|
+
const y = node<ReturnType>('define', { id, layout }, x, ...args)
|
|
131
133
|
scoped(x, () => fun(paramVars), y)
|
|
132
134
|
return y
|
|
133
135
|
}
|
|
134
|
-
ret.setLayout = (_layout: FnLayout) =>
|
|
136
|
+
ret.setLayout = (_layout: FnLayout) => {
|
|
137
|
+
layout = _layout
|
|
138
|
+
return ret
|
|
139
|
+
}
|
|
135
140
|
return ret
|
|
136
141
|
}
|