glre 0.28.0 → 0.29.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/src/node/code.ts CHANGED
@@ -1,67 +1,72 @@
1
1
  import { is } from '../utils/helpers'
2
2
  import { infer } from './infer'
3
- import { joins, getOperator, formatConversions } from './utils'
3
+ import { joins, getOperator, formatConversions, generateDefine } from './utils'
4
+ import { WGSL_TO_GLSL_BUILTIN } from './const'
4
5
  import type { NodeConfig, X } from './types'
5
6
 
6
7
  export const code = (target: X, c?: NodeConfig | null): string => {
7
8
  if (!c) c = {}
8
- if (!c.uniforms) c.uniforms = new Set()
9
- if (!c.functions) c.functions = new Set()
10
- if (is.num(target)) return target.toFixed(1)
9
+ if (!c.headers) c.headers = new Map()
11
10
  if (is.str(target)) return target
12
- if (is.bol(target)) return target.toString()
11
+ if (is.num(target)) return target.toFixed(1)
12
+ if (is.bol(target)) return target ? 'true' : 'false'
13
13
  if (!target) return '' // ignore if no target
14
14
  const { type, props } = target
15
15
  const { id = '', children = [] } = props
16
16
  const [x, y, z] = children
17
+ let head = ''
17
18
  if (type === 'uniform') {
19
+ if (c.headers.has(id)) return id
20
+ if (!c.binding) c.binding = 0
18
21
  const varType = infer(target, c)
19
- c.uniforms.add(`${varType} ${id}`)
20
- c.onUniform?.(id, props.value)
22
+ head = c.isWebGL
23
+ ? `uniform ${varType} ${id};`
24
+ : `@group(0) @binding(${c.binding++}) var<uniform> ${id}: ${formatConversions(varType, c)};`
25
+ }
26
+ if (type === 'attribute') {
27
+ if (c.headers.has(id)) return id
28
+ head = `${infer(target, c)} ${id}`
29
+ }
30
+ if (type === 'constant') {
31
+ if (c.headers.has(id)) return id
32
+ head = `${infer(target, c)} ${id}`
33
+ }
34
+ if (type === 'varying') {
35
+ if (c.headers.has(id)) return id
36
+ head = `${infer(target, c)} ${id}`
37
+ }
38
+ if (head) {
39
+ c.headers.set(id, head)
40
+ c.onMount?.(id, props.value)
21
41
  return id
22
42
  }
23
- if (type === 'variable' || type === 'varying' || type === 'constant' || type === 'attribute') return id
24
- if (type === 'vertex_stage') return code(x, c)
43
+ if (type === 'variable') return id
25
44
  if (type === 'swizzle') return `${code(y, c)}.${code(x, c)}`
26
45
  if (type === 'operator') {
27
46
  if (x === 'not' || x === 'bitNot') return `!${code(y, c)}`
28
47
  return `(${code(y, c)} ${getOperator(x)} ${code(z, c)})`
29
48
  }
30
- if (type === 'math_fun') return `${x}(${joins(children.slice(1), c)})`
31
- if (type === 'conversions') return `${formatConversions(x, c)}(${joins(children.slice(1), c)})`
49
+ if (type === 'function') {
50
+ // Handle special functions that need to be converted to operators
51
+ if (x === 'negate') return `(-${joins(children.slice(1), c)})`
52
+ return `${x}(${joins(children.slice(1), c)})`
53
+ }
54
+ if (type === 'conversion') return `${formatConversions(x, c)}(${joins(children.slice(1), c)})`
32
55
  if (type === 'scope') return children.map((child: any) => code(child, c)).join('\n')
33
56
  if (type === 'assign') return `${code(x, c)} = ${code(y, c)};`
34
- if (type === 'fn_run') {
35
- c.functions.add(code(x, c))
36
- return `${id}(${children
37
- .slice(1)
38
- .map((child) => code(child, c))
39
- .join(', ')})`
40
- }
41
- if (type === 'fn_def') {
42
- const { paramInfo = [], returnType } = props
43
- const scopeCode = code(x, c)
44
- const returnCode = y ? `return ${code(y, c)};` : ''
45
- if (c?.isWebGL) {
46
- const params = paramInfo.map(({ name, type }) => `${type} ${name}`).join(', ')
47
- return `${returnType} ${id}(${params}) {\n${scopeCode}\n${returnCode}\n}`
48
- } else {
49
- const wgslReturnType = formatConversions(returnType, c)
50
- const wgslParams = paramInfo
51
- .map(({ name, type }) => {
52
- const wgslParamType = formatConversions(type, c)
53
- return `${name}: ${wgslParamType}`
54
- })
55
- .join(', ')
56
- return `fn ${id}(${wgslParams}) -> ${wgslReturnType} {\n${scopeCode}\n${returnCode}\n}`
57
- }
57
+ if (type === 'define') {
58
+ const args = children.slice(2)
59
+ const ret = `${id}(${args.map((arg) => code(arg, c))})`
60
+ if (c.headers.has(id)) return ret
61
+ c.headers.set(id, generateDefine(props, c))
62
+ return ret
58
63
  }
59
64
  if (type === 'loop') return `for (int i = 0; i < ${x}; i++) {\n${code(y, c)}\n}`
60
65
  if (type === 'if') {
61
66
  let ret = `if (${code(x, c)}) {\n${code(y, c)}\n}`
62
67
  for (let i = 2; i < children.length; i += 2) {
63
- const isLast = i >= children.length - 1
64
- ret += !isLast
68
+ const isElseIf = i >= children.length - 1
69
+ ret += !isElseIf
65
70
  ? ` else if (${code(children[i], c)}) {\n${code(children[i + 1], c)}\n}`
66
71
  : ` else {\n${code(children[i], c)}\n}`
67
72
  }
@@ -69,21 +74,16 @@ export const code = (target: X, c?: NodeConfig | null): string => {
69
74
  }
70
75
  if (type === 'switch') {
71
76
  let ret = `switch (${code(x, c)}) {\n`
72
- for (const child of children.slice(1)) ret += code(child, c) + '\n'
73
- ret += '}'
74
- return ret
75
- }
76
- if (type === 'case') {
77
- const values = children.slice(0, -1)
78
- const scope = children[children.length - 1]
79
- let ret = ''
80
- for (const value of values) {
81
- ret += `case ${code(value, c)}:\n`
77
+ for (let i = 1; i < children.length; i += 2) {
78
+ const isDefault = i >= children.length - 1
79
+ if (isDefault && children.length % 2 === 0) {
80
+ ret += `default:\n${code(children[i], c)}\nbreak;\n`
81
+ } else if (i + 1 < children.length)
82
+ ret += `case ${code(children[i], c)}:\n${code(children[i + 1], c)}\nbreak;\n`
82
83
  }
83
- ret += `${code(scope, c)}\nbreak;\n`
84
+ ret += '}'
84
85
  return ret
85
86
  }
86
- if (type === 'default') `default:\n${code(x, c)}\nbreak;\n`
87
87
  if (type === 'ternary') return `(${code(x, c)} ? ${code(y, c)} : ${code(z, c)})`
88
88
  if (type === 'declare') {
89
89
  const varType = infer(y, c)
@@ -94,7 +94,8 @@ export const code = (target: X, c?: NodeConfig | null): string => {
94
94
  }
95
95
  if (type === 'builtin') {
96
96
  if (c?.isWebGL) {
97
- if (id === 'position') return 'gl_FragCoord'
97
+ const glslBuiltin = WGSL_TO_GLSL_BUILTIN[id as keyof typeof WGSL_TO_GLSL_BUILTIN]
98
+ if (glslBuiltin) return glslBuiltin
98
99
  if (id === 'uv') return 'gl_FragCoord.xy'
99
100
  }
100
101
  return id
package/src/node/const.ts CHANGED
@@ -69,7 +69,6 @@ export const OPERATORS = {
69
69
 
70
70
  export const OPERATOR_KEYS = Object.keys(OPERATORS) as (keyof typeof OPERATORS)[]
71
71
 
72
- // Function return type classification
73
72
  export const SCALAR_RETURN_FUNCTIONS = ['dot', 'distance', 'length', 'lengthSq', 'determinant', 'luminance'] as const
74
73
 
75
74
  export const BOOL_RETURN_FUNCTIONS = ['all', 'any'] as const
@@ -171,8 +170,37 @@ export const COMPONENT_COUNT_TO_TYPE = {
171
170
  } as const
172
171
 
173
172
  export const BUILTIN_TYPES = {
173
+ // WGSL builtin variables
174
+ position: 'vec4',
175
+ vertex_index: 'uint',
176
+ instance_index: 'uint',
177
+ front_facing: 'bool',
178
+ frag_depth: 'float',
179
+ sample_index: 'uint',
180
+ sample_mask: 'uint',
181
+ point_coord: 'vec2',
182
+
183
+ // TSL compatible variables
184
+ positionLocal: 'vec3',
185
+ positionWorld: 'vec3',
186
+ positionView: 'vec3',
187
+ normalLocal: 'vec3',
188
+ normalWorld: 'vec3',
189
+ normalView: 'vec3',
190
+ screenCoordinate: 'vec2',
191
+ screenUV: 'vec2',
192
+
193
+ // Legacy GLSL variables (for backward compatibility)
174
194
  gl_FragCoord: 'vec4',
175
- position: 'vec3',
195
+ gl_VertexID: 'uint',
196
+ gl_InstanceID: 'uint',
197
+ gl_FrontFacing: 'bool',
198
+ gl_FragDepth: 'float',
199
+ gl_SampleID: 'uint',
200
+ gl_SampleMask: 'uint',
201
+ gl_PointCoord: 'vec2',
202
+
203
+ // Common variables
176
204
  normal: 'vec3',
177
205
  uv: 'vec2',
178
206
  color: 'vec4',
@@ -188,3 +216,14 @@ export const COMPARISON_OPERATORS = [
188
216
  ] as const
189
217
 
190
218
  export const LOGICAL_OPERATORS = ['and', 'or'] as const
219
+
220
+ export const WGSL_TO_GLSL_BUILTIN = {
221
+ position: 'gl_FragCoord',
222
+ vertex_index: 'gl_VertexID',
223
+ instance_index: 'gl_InstanceID',
224
+ front_facing: 'gl_FrontFacing',
225
+ frag_depth: 'gl_FragDepth',
226
+ sample_index: 'gl_SampleID',
227
+ sample_mask: 'gl_SampleMask',
228
+ point_coord: 'gl_PointCoord',
229
+ } as const
package/src/node/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { f, n, node, u } from './node'
1
+ import { conversion as c, function_ as f, node } from './node'
2
2
  import { hex2rgb } from './utils'
3
3
  import { is } from '../utils/helpers'
4
4
  import type { X } from './types'
@@ -10,20 +10,33 @@ export * from './scope'
10
10
  export * from './types'
11
11
  export * from './utils'
12
12
 
13
+ // x ? y : z
14
+ export const select = (x: X, y: X, z: X) => node('ternary', null, x, y, z)
15
+
16
+ // uniform and attribute
17
+ export const uniform = (value: number | number[], id?: string) => node('uniform', { id, value })
18
+ export const varying = (value: number | number[], id?: string) => node('varying', { id, value })
19
+ export const attribute = (value: number | number[], id?: string) => node('varying', { id, value })
20
+ export const variable = (id: string) => node('variable', { id })
21
+ export const builtin = (id: string) => node('builtin', { id })
22
+
13
23
  // Default uniforms
14
- export const iResolution = u('iResolution', [1280, 800])
15
- export const iMouse = u('iMouse', [0, 0])
16
- export const iTime = u('iTime', 0)
17
- export const position = node('variable', { id: 'gl_FragCoord' })
24
+ export const iResolution = uniform([1280, 800], 'iResolution')
25
+ export const iMouse = uniform([0, 0], 'iMouse')
26
+ export const iTime = uniform(0, 'iTime')
18
27
 
19
- // Default attributes
20
- export const uv = (index = 0) => node('attribute', { id: `uv${index || ''}` })
21
- export const vertexColor = (index = 0) => node('attribute', { id: `color${index || ''}` })
22
- export const attribute = (id: string, type?: string) => node('attribute', { id, type })
23
- export const vertexStage = (value: X) => node('vertex_stage', null, value)
28
+ // Builtin Variables
29
+ export const position = node('builtin', { id: 'position' })
30
+ export const vertexIndex = node('builtin', { id: 'vertex_index' })
31
+ export const instanceIndex = node('builtin', { id: 'instance_index' })
32
+ export const frontFacing = node('builtin', { id: 'front_facing' })
33
+ export const fragDepth = node('builtin', { id: 'frag_depth' })
34
+ export const sampleIndex = node('builtin', { id: 'sample_index' })
35
+ export const sampleMask = node('builtin', { id: 'sample_mask' })
36
+ export const pointCoord = node('builtin', { id: 'point_coord' })
24
37
 
25
- // Buildin Variables
26
- export const positionLocal = node('builtin', { id: 'positionLocal' })
38
+ // TSL Compatible Builtin Variables
39
+ export const positionLocal = node('builtin', { id: 'position' })
27
40
  export const positionWorld = node('builtin', { id: 'positionWorld' })
28
41
  export const positionView = node('builtin', { id: 'positionView' })
29
42
  export const normalLocal = node('builtin', { id: 'normalLocal' })
@@ -32,26 +45,30 @@ export const normalView = node('builtin', { id: 'normalView' })
32
45
  export const screenCoordinate = node('builtin', { id: 'screenCoordinate' })
33
46
  export const screenUV = node('builtin', { id: 'screenUV' })
34
47
 
48
+ // Legacy aliases for backward compatibility
49
+ export const fragCoord = position
50
+ export const vertexId = vertexIndex
51
+
35
52
  // Type constructors
36
- export const float = (x: X) => n('float', x)
37
- export const int = (x: X) => n('int', x)
38
- export const uint = (x: X) => n('uint', x)
39
- export const bool = (x: X) => n('bool', x)
40
- export const vec2 = (x?: X, y?: X) => n('vec2', x, y)
41
- export const vec3 = (x?: X, y?: X, z?: X) => n('vec3', x, y, z)
42
- export const vec4 = (x?: X, y?: X, z?: X, w?: X) => n('vec4', x, y, z, w)
43
- export const mat2 = (...args: X[]) => n('mat2', ...args)
44
- export const mat3 = (...args: X[]) => n('mat3', ...args)
45
- export const mat4 = (...args: X[]) => n('mat4', ...args)
46
- export const ivec2 = (x?: X, y?: X) => n('ivec2', x, y)
47
- export const ivec3 = (x?: X, y?: X, z?: X) => n('ivec3', x, y, z)
48
- export const ivec4 = (x?: X, y?: X, z?: X, w?: X) => n('ivec4', x, y, z, w)
49
- export const uvec2 = (x?: X, y?: X) => n('uvec2', x, y)
50
- export const uvec3 = (x?: X, y?: X, z?: X) => n('uvec3', x, y, z)
51
- export const uvec4 = (x?: X, y?: X, z?: X, w?: X) => n('uvec4', x, y, z, w)
52
- export const bvec2 = (x?: X, y?: X) => n('bvec2', x, y)
53
- export const bvec3 = (x?: X, y?: X, z?: X) => n('bvec3', x, y, z)
54
- export const bvec4 = (x?: X, y?: X, z?: X, w?: X) => n('bvec4', x, y, z, w)
53
+ export const float = (x: X) => c('float', x)
54
+ export const int = (x: X) => c('int', x)
55
+ export const uint = (x: X) => c('uint', x)
56
+ export const bool = (x: X) => c('bool', x)
57
+ export const vec2 = (x?: X, y?: X) => c('vec2', x, y)
58
+ export const vec3 = (x?: X, y?: X, z?: X) => c('vec3', x, y, z)
59
+ export const vec4 = (x?: X, y?: X, z?: X, w?: X) => c('vec4', x, y, z, w)
60
+ export const mat2 = (...args: X[]) => c('mat2', ...args)
61
+ export const mat3 = (...args: X[]) => c('mat3', ...args)
62
+ export const mat4 = (...args: X[]) => c('mat4', ...args)
63
+ export const ivec2 = (x?: X, y?: X) => c('ivec2', x, y)
64
+ export const ivec3 = (x?: X, y?: X, z?: X) => c('ivec3', x, y, z)
65
+ export const ivec4 = (x?: X, y?: X, z?: X, w?: X) => c('ivec4', x, y, z, w)
66
+ export const uvec2 = (x?: X, y?: X) => c('uvec2', x, y)
67
+ export const uvec3 = (x?: X, y?: X, z?: X) => c('uvec3', x, y, z)
68
+ export const uvec4 = (x?: X, y?: X, z?: X, w?: X) => c('uvec4', x, y, z, w)
69
+ export const bvec2 = (x?: X, y?: X) => c('bvec2', x, y)
70
+ export const bvec3 = (x?: X, y?: X, z?: X) => c('bvec3', x, y, z)
71
+ export const bvec4 = (x?: X, y?: X, z?: X, w?: X) => c('bvec4', x, y, z, w)
55
72
  export const color = (r?: X, g?: X, b?: X) => {
56
73
  if (is.num(r) && is.und(g) && is.und(b)) return vec3(...hex2rgb(r))
57
74
  return vec3(r, g, b)
package/src/node/infer.ts CHANGED
@@ -14,11 +14,11 @@ import {
14
14
  COMPONENT_COUNT_TO_TYPE,
15
15
  BUILTIN_TYPES,
16
16
  } from './const'
17
- import type { Constants, NodeConfig, X } from './types'
17
+ import type { Constants, NodeConfig, NodeProxy, X } from './types'
18
18
 
19
19
  const inferPrimitiveType = (x: any): Constants => {
20
20
  if (is.bol(x)) return 'bool'
21
- if (is.num(x)) return Number.isInteger(x) ? 'int' : 'float'
21
+ if (is.num(x)) return 'float' // Number.isInteger(x) ? 'int' : 'float' // @TODO FIX
22
22
  if (is.arr(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] || 'float'
23
23
  return 'float'
24
24
  }
@@ -34,40 +34,38 @@ const inferBinaryOpType = (leftType: string, rightType: string, op: string): Con
34
34
  return (leftPriority >= rightPriority ? leftType : rightType) as Constants
35
35
  }
36
36
 
37
- const getHighestPriorityType = (args: X[]) => {
37
+ const getHighestPriorityType = (args: X[], c: NodeConfig) => {
38
38
  return args.reduce((highest, current) => {
39
- const currentType = infer(current)
39
+ const currentType = infer(current, c)
40
40
  const highestPriority = CONSTANTS.indexOf(highest as any)
41
41
  const currentPriority = CONSTANTS.indexOf(currentType as any)
42
42
  return currentPriority > highestPriority ? currentType : highest
43
- }, 'float')
43
+ }, 'float') as Constants
44
44
  }
45
+
45
46
  const inferSwizzleType = (count: number): Constants => {
46
- return COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE] || 'vec4'
47
+ return COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE]!
47
48
  }
48
49
 
49
50
  const inferBuiltinType = (id: string | undefined): Constants => {
50
- if (!id) return 'vec3'
51
51
  return BUILTIN_TYPES[id as keyof typeof BUILTIN_TYPES]!
52
52
  }
53
53
 
54
- const inferMathType = (funcName: string, args: X[]): Constants => {
55
- const firstArgType = args.length > 0 ? infer(args[0]) : 'float'
56
- if (FIRST_ARG_TYPE_FUNCTIONS.includes(funcName as any)) return firstArgType as Constants
54
+ const inferMathType = (funcName: string, args: X[], c: NodeConfig): Constants => {
55
+ const firstArgType = args.length > 0 ? infer(args[0], c) : 'float'
56
+ if (FIRST_ARG_TYPE_FUNCTIONS.includes(funcName as any)) return firstArgType
57
57
  if (SCALAR_RETURN_FUNCTIONS.includes(funcName as any)) return 'float'
58
58
  if (BOOL_RETURN_FUNCTIONS.includes(funcName as any)) return 'bool'
59
- if (PRESERVE_TYPE_FUNCTIONS.includes(funcName as any)) return firstArgType as Constants
59
+ if (PRESERVE_TYPE_FUNCTIONS.includes(funcName as any)) return firstArgType
60
60
  if (VEC3_RETURN_FUNCTIONS.includes(funcName as any)) return 'vec3'
61
61
  if (VEC4_RETURN_FUNCTIONS.includes(funcName as any)) return 'vec4'
62
- if (HIGHEST_TYPE_FUNCTIONS.includes(funcName as any)) return getHighestPriorityType(args) as Constants
63
- return firstArgType as Constants
62
+ if (HIGHEST_TYPE_FUNCTIONS.includes(funcName as any)) return getHighestPriorityType(args, c)
63
+ return firstArgType
64
64
  }
65
65
 
66
- export const infer = (target: X, c?: NodeConfig): Constants => {
67
- if (!target) throw ``
68
- if (!isNodeProxy(target)) return inferPrimitiveType(target)
66
+ export const inferImpl = (target: NodeProxy, c: NodeConfig): Constants => {
69
67
  const { type, props } = target
70
- const { id, children = [], value, returnType } = props
68
+ const { id, children = [], value } = props
71
69
  const [x, y, z] = children
72
70
  if (
73
71
  type === 'uniform' ||
@@ -77,17 +75,22 @@ export const infer = (target: X, c?: NodeConfig): Constants => {
77
75
  type === 'varying'
78
76
  )
79
77
  return inferPrimitiveType(value)
80
- if (type === 'conversions') return x as Constants
78
+ if (type === 'conversion') return x as Constants
81
79
  if (type === 'operator') return inferBinaryOpType(infer(y, c), infer(z, c), x as string)
82
- if (type === 'math_fun') return inferMathType(x as string, children.slice(1))
80
+ if (type === 'function') return inferMathType(x as string, children.slice(1), c)
83
81
  if (type === 'swizzle') return inferSwizzleType((x as string).length)
84
82
  if (type === 'ternary') return inferBinaryOpType(infer(y, c), infer(z, c), 'add')
85
- if (type === 'fn_run') return returnType!
86
- if (type === 'fn_def') return returnType!
83
+ if (type === 'define') return y ? infer(y, c) : 'void'
87
84
  if (type === 'builtin') return inferBuiltinType(id)
88
85
  return 'float'
89
86
  }
90
87
 
91
- export const inferParameterTypes = (args: X[], c?: NodeConfig): Constants[] => {
92
- return args.map((arg) => infer(arg, c))
88
+ export const infer = (target: X, c: NodeConfig | null): Constants => {
89
+ if (!c) c = {}
90
+ if (!isNodeProxy(target)) return inferPrimitiveType(target)
91
+ if (!c.infers) c.infers = new WeakMap<NodeProxy, Constants>()
92
+ if (c.infers.has(target)) return c.infers.get(target)!
93
+ const ret = inferImpl(target, c)
94
+ c.infers.set(target, ret)
95
+ return ret
93
96
  }
package/src/node/node.ts CHANGED
@@ -1,51 +1,42 @@
1
1
  import { code } from './code'
2
- import { assign, toVar, toConst } from './scope'
2
+ import { assign, toVar } from './scope'
3
3
  import { getId, isConversion, isFunction, isOperator, isSwizzle } from './utils'
4
4
  import type { Functions, NodeProps, NodeProxy, NodeTypes, Operators, Swizzles, X } from './types'
5
5
 
6
- const toPrimitive = (x: X) => {
7
- return (hint: string) => {
8
- if (hint === 'string') return code(x)
9
- }
6
+ const toPrimitive = (x: X, hint: string) => {
7
+ if (hint === 'string') return code(x)
10
8
  }
11
9
 
12
10
  export const node = (type: NodeTypes, props?: NodeProps | null, ...args: X[]) => {
13
11
  if (!props) props = {}
14
12
  if (args.length) props.children = args
15
- const x = new Proxy(() => {}, {
16
- get(_, key) {
17
- if (key === 'type') return type
18
- if (key === 'props') return props
19
- if (key === 'toVar') return toVar(x)
20
- if (key === 'toConst') return toConst(x)
21
- if (key === 'assign') return assign(x)
22
- if (key === 'isProxy') return true
23
- if (key === 'toString') return code.bind(null, x)
24
- if (key === Symbol.toPrimitive) return toPrimitive(x)
25
- if (isSwizzle(key)) return s(key, x)
26
- if (isOperator(key)) return (...y: X[]) => o(key, x, ...y)
27
- if (isFunction(key)) return (...y: X[]) => f(key, x, ...y)
28
- if (isConversion(key)) return n(key, x)
29
- },
30
- set(_, key, value) {
31
- if (isSwizzle(key)) {
32
- s(key, x).assign(value)
33
- return true
34
- }
35
- return false
36
- },
37
- }) as unknown as NodeProxy
13
+ const get = (_: unknown, key: string | Symbol) => {
14
+ if (key === 'type') return type
15
+ if (key === 'props') return props
16
+ if (key === 'toVar') return toVar.bind(null, x)
17
+ if (key === 'assign') return assign.bind(null, x)
18
+ if (key === 'isProxy') return true
19
+ if (key === 'toString') return code.bind(null, x)
20
+ if (key === Symbol.toPrimitive) return toPrimitive.bind(null, x)
21
+ if (isSwizzle(key)) return swizzle(key, x)
22
+ if (isOperator(key)) return (...y: X[]) => operator(key, x, ...y)
23
+ if (isFunction(key)) return (...y: X[]) => function_(key, x, ...y)
24
+ if (isConversion(key)) return conversion(key, x)
25
+ }
26
+ const set = (_: unknown, key: string, value: X) => {
27
+ if (isSwizzle(key)) {
28
+ swizzle(key, x).assign(value)
29
+ return true
30
+ }
31
+ return false
32
+ }
33
+ const x = new Proxy({}, { get, set }) as unknown as NodeProxy
38
34
  return x
39
35
  }
40
36
 
41
37
  // Node shorthands
42
- export const v = (...args: X[]) => node('variable', { id: getId() }, ...args)
43
- export const s = (key: Swizzles, arg: X) => node('swizzle', null, key, arg)
44
- export const n = (key: string, ...args: X[]) => node('conversions', null, key, ...args)
45
- export const o = (key: Operators, ...args: X[]) => node('operator', null, key, ...args)
46
- export const f = (key: Functions, ...args: X[]) => node('math_fun', null, key, ...args)
47
-
48
- // uniform and attribute
49
- export const u = (id: string, value?: number | number[] | boolean) => node('uniform', { id, value })
50
-
51
- export const select = (x: X, y: X, z: X) => node('ternary', null, x, y, z)
38
+ export const variable = (...args: X[]) => node('variable', { id: getId() }, ...args)
39
+ export const swizzle = (key: Swizzles, arg: X) => node('swizzle', null, key, arg)
40
+ export const operator = (key: Operators, ...args: X[]) => node('operator', null, key, ...args)
41
+ export const function_ = (key: Functions, ...args: X[]) => node('function', null, key, ...args)
42
+ export const conversion = (key: string, ...args: X[]) => node('conversion', null, key, ...args)
package/src/node/scope.ts CHANGED
@@ -1,14 +1,13 @@
1
- import { infer } from './infer'
2
1
  import { node } from './node'
3
2
  import { getId } from './utils'
4
3
  import type { NodeProxy, X } from './types'
5
4
 
6
5
  let _scope: NodeProxy | null = null
7
6
 
8
- const scoped = (x: NodeProxy | null, callback = () => {}) => {
7
+ const scoped = (x: NodeProxy | null, fun = () => {}) => {
9
8
  const prev = _scope
10
9
  _scope = x
11
- callback()
10
+ fun()
12
11
  _scope = prev
13
12
  }
14
13
 
@@ -18,30 +17,44 @@ const addToScope = (x: NodeProxy) => {
18
17
  _scope.props.children.push(x)
19
18
  }
20
19
 
21
- export const If = (condition: X, callback: () => void) => {
20
+ export const toVar = (x: X, id?: string) => {
21
+ if (!id) id = getId()
22
+ const y = node('variable', { id })
23
+ const z = node('declare', null, y, x)
24
+ addToScope(z)
25
+ return y
26
+ }
27
+
28
+ export const assign = (x: X, y: X) => {
29
+ const z = node('assign', null, x, y)
30
+ addToScope(z)
31
+ return x
32
+ }
33
+
34
+ export const If = (condition: X, fun: () => void) => {
22
35
  const scope = node('scope')
23
- scoped(scope, callback)
36
+ scoped(scope, fun)
24
37
  const ifNode = node('if', null, condition, scope)
25
38
  addToScope(ifNode)
26
39
  const createChain = () => ({
27
- ElseIf: (newCondition: X, elseIfCallback: () => void) => {
28
- const elseIfScope = node('scope')
29
- scoped(elseIfScope, elseIfCallback)
30
- ifNode.props.children!.push(newCondition, elseIfScope)
40
+ ElseIf: (x: X, _fun: () => void) => {
41
+ const y = node('scope')
42
+ scoped(y, _fun)
43
+ ifNode.props.children!.push(x, y)
31
44
  return createChain()
32
45
  },
33
- Else: (elseCallback: () => void) => {
34
- const elseScope = node('scope')
35
- scoped(elseScope, elseCallback)
36
- ifNode.props.children!.push(elseScope)
46
+ Else: (_fun: () => void) => {
47
+ const x = node('scope')
48
+ scoped(x, _fun)
49
+ ifNode.props.children!.push(x)
37
50
  },
38
51
  })
39
52
  return createChain()
40
53
  }
41
54
 
42
- export const Loop = (x: X, callback?: (params: { i: NodeProxy }) => void) => {
55
+ export const Loop = (x: X, fun: (params: { i?: NodeProxy }) => void) => {
43
56
  const y = node('scope')
44
- scoped(y, () => callback?.({ i: node('variable', { id: 'i' }) }))
57
+ scoped(y, () => fun({ i: node('variable', { id: 'i' }) }))
45
58
  const ret = node('loop', null, x, y)
46
59
  addToScope(ret)
47
60
  return ret
@@ -52,28 +65,29 @@ export const Switch = (value: X) => {
52
65
  addToScope(switchNode)
53
66
  const createChain = () => ({
54
67
  Case: (...values: X[]) => {
55
- return (callback: () => void) => {
56
- const caseScope = node('scope')
57
- scoped(caseScope, callback)
58
- const caseNode = node('case', null, ...values, caseScope)
59
- switchNode.props.children!.push(caseNode)
68
+ return (fun: () => void) => {
69
+ const scope = node('scope')
70
+ scoped(scope, fun)
71
+ // 複数のcase値を処理
72
+ for (const val of values) {
73
+ switchNode.props.children!.push(val, scope)
74
+ }
60
75
  return createChain()
61
76
  }
62
77
  },
63
- Default: (callback: () => void) => {
64
- const defaultScope = node('scope')
65
- scoped(defaultScope, callback)
66
- const defaultNode = node('default', null, defaultScope)
67
- switchNode.props.children!.push(defaultNode)
78
+ Default: (fun: () => void) => {
79
+ const scope = node('scope')
80
+ scoped(scope, fun)
81
+ switchNode.props.children!.push(scope)
68
82
  },
69
83
  })
70
84
 
71
85
  return createChain()
72
86
  }
73
87
 
74
- export const Fn = (callback: (args: NodeProxy[]) => NodeProxy) => {
88
+ export const Fn = (fun: (paramVars: NodeProxy[]) => NodeProxy) => {
75
89
  const id = getId()
76
- return (...args: NodeProxy[]) => {
90
+ return (...args: X[]) => {
77
91
  const x = node('scope')
78
92
  let y: NodeProxy | undefined
79
93
  const paramVars: NodeProxy[] = []
@@ -82,40 +96,7 @@ export const Fn = (callback: (args: NodeProxy[]) => NodeProxy) => {
82
96
  const paramVar = node('variable', { id: paramId })
83
97
  paramVars.push(paramVar)
84
98
  }
85
- scoped(x, () => (y = callback(paramVars)))
86
- const returnType = y ? infer(y) : 'void'
87
- const paramInfo = args.map((arg, i) => ({ name: `p${i}`, type: infer(arg) }))
88
- const def = node('fn_def', { id, returnType, paramInfo, args }, x, y)
89
- return node('fn_run', { id, returnType }, def, ...paramVars)
99
+ scoped(x, () => (y = fun(paramVars)))
100
+ return node('define', { id }, x, y, ...args)
90
101
  }
91
102
  }
92
-
93
- export const toVar = (x: X) => (id?: string) => {
94
- if (!id) id = getId()
95
- const y = node('variable', { id })
96
- const z = node('declare', null, y, x)
97
- addToScope(z)
98
- return y
99
- }
100
-
101
- export const toConst = (x: X) => (id?: string) => {
102
- if (!id) id = getId()
103
- const y = node('constant', { id })
104
- const z = node('declare', null, y, x)
105
- addToScope(z)
106
- return y
107
- }
108
-
109
- export const assign = (x: X) => (y: X) => {
110
- const assignNode = node('assign', null, x, y)
111
- addToScope(assignNode)
112
- return x
113
- }
114
-
115
- export const varying = (value: X, name?: string) => {
116
- if (!name) name = getId()
117
- const varyingVar = node('varying', { id: name })
118
- const declaration = node('declare', null, varyingVar, value)
119
- addToScope(declaration)
120
- return varyingVar
121
- }