glre 0.29.0 → 0.30.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,20 +1,30 @@
1
1
  import { is } from '../utils/helpers'
2
2
  import { infer } from './infer'
3
- import { joins, getOperator, formatConversions, generateDefine } from './utils'
4
- import { WGSL_TO_GLSL_BUILTIN } from './const'
3
+ import { getBluiltin, getOperator, generateDefine, formatConversions, joins } from './utils'
5
4
  import type { NodeConfig, X } from './types'
6
5
 
7
6
  export const code = (target: X, c?: NodeConfig | null): string => {
8
7
  if (!c) c = {}
9
8
  if (!c.headers) c.headers = new Map()
10
9
  if (is.str(target)) return target
11
- if (is.num(target)) return target.toFixed(1)
10
+ if (is.num(target)) {
11
+ const ret = `${target}`
12
+ if (ret.includes('.')) return ret
13
+ return ret + '.0'
14
+ }
12
15
  if (is.bol(target)) return target ? 'true' : 'false'
13
16
  if (!target) return '' // ignore if no target
14
17
  const { type, props } = target
15
18
  const { id = '', children = [] } = props
16
19
  const [x, y, z] = children
20
+ /**
21
+ * headers
22
+ */
17
23
  let head = ''
24
+ if (type === 'attribute') {
25
+ if (c.headers.has(id)) return id
26
+ head = `${infer(target, c)} ${id}`
27
+ }
18
28
  if (type === 'uniform') {
19
29
  if (c.headers.has(id)) return id
20
30
  if (!c.binding) c.binding = 0
@@ -23,13 +33,13 @@ export const code = (target: X, c?: NodeConfig | null): string => {
23
33
  ? `uniform ${varType} ${id};`
24
34
  : `@group(0) @binding(${c.binding++}) var<uniform> ${id}: ${formatConversions(varType, c)};`
25
35
  }
26
- if (type === 'attribute') {
27
- if (c.headers.has(id)) return id
28
- head = `${infer(target, c)} ${id}`
29
- }
30
36
  if (type === 'constant') {
31
37
  if (c.headers.has(id)) return id
32
- head = `${infer(target, c)} ${id}`
38
+ const varType = infer(target, c)
39
+ const value = code(x, c)
40
+ head = c.isWebGL
41
+ ? `const ${varType} ${id} = ${value};`
42
+ : `const ${id}: ${formatConversions(varType, c)} = ${value};`
33
43
  }
34
44
  if (type === 'varying') {
35
45
  if (c.headers.has(id)) return id
@@ -37,23 +47,34 @@ export const code = (target: X, c?: NodeConfig | null): string => {
37
47
  }
38
48
  if (head) {
39
49
  c.headers.set(id, head)
40
- c.onMount?.(id, props.value)
50
+ c.onMount?.(id)
41
51
  return id
42
52
  }
53
+ /**
54
+ * variables
55
+ */
43
56
  if (type === 'variable') return id
44
57
  if (type === 'swizzle') return `${code(y, c)}.${code(x, c)}`
58
+ if (type === 'ternary') return `(${code(x, c)} ? ${code(y, c)} : ${code(z, c)})`
59
+ if (type === 'builtin') return c?.isWebGL ? getBluiltin(id) : id
60
+ if (type === 'conversion') return `${formatConversions(x, c)}(${joins(children.slice(1), c)})`
45
61
  if (type === 'operator') {
46
62
  if (x === 'not' || x === 'bitNot') return `!${code(y, c)}`
47
63
  return `(${code(y, c)} ${getOperator(x)} ${code(z, c)})`
48
64
  }
49
65
  if (type === 'function') {
50
- // Handle special functions that need to be converted to operators
51
66
  if (x === 'negate') return `(-${joins(children.slice(1), c)})`
52
67
  return `${x}(${joins(children.slice(1), c)})`
53
68
  }
54
- if (type === 'conversion') return `${formatConversions(x, c)}(${joins(children.slice(1), c)})`
69
+ /**
70
+ * scopes
71
+ */
55
72
  if (type === 'scope') return children.map((child: any) => code(child, c)).join('\n')
56
73
  if (type === 'assign') return `${code(x, c)} = ${code(y, c)};`
74
+ if (type === 'loop')
75
+ return c.isWebGL
76
+ ? `for (int i = 0; i < ${x}; i += 1) {\n${code(y, c)}\n}`
77
+ : `for (var i: i32 = 0; i < ${x}; i++) {\n${code(y, c)}\n}`
57
78
  if (type === 'define') {
58
79
  const args = children.slice(2)
59
80
  const ret = `${id}(${args.map((arg) => code(arg, c))})`
@@ -61,7 +82,6 @@ export const code = (target: X, c?: NodeConfig | null): string => {
61
82
  c.headers.set(id, generateDefine(props, c))
62
83
  return ret
63
84
  }
64
- if (type === 'loop') return `for (int i = 0; i < ${x}; i++) {\n${code(y, c)}\n}`
65
85
  if (type === 'if') {
66
86
  let ret = `if (${code(x, c)}) {\n${code(y, c)}\n}`
67
87
  for (let i = 2; i < children.length; i += 2) {
@@ -84,21 +104,12 @@ export const code = (target: X, c?: NodeConfig | null): string => {
84
104
  ret += '}'
85
105
  return ret
86
106
  }
87
- if (type === 'ternary') return `(${code(x, c)} ? ${code(y, c)} : ${code(z, c)})`
88
107
  if (type === 'declare') {
89
- const varType = infer(y, c)
90
- const varName = (x as any)?.props?.id
91
- if (c.isWebGL) return `${varType} ${varName} = ${code(y, c)};`
108
+ const varType = infer(x, c)
109
+ const varName = (y as any)?.props?.id
110
+ if (c.isWebGL) return `${varType} ${varName} = ${code(x, c)};`
92
111
  const wgslType = formatConversions(varType)
93
- return `var ${varName}: ${wgslType} = ${code(y, c)};`
94
- }
95
- if (type === 'builtin') {
96
- if (c?.isWebGL) {
97
- const glslBuiltin = WGSL_TO_GLSL_BUILTIN[id as keyof typeof WGSL_TO_GLSL_BUILTIN]
98
- if (glslBuiltin) return glslBuiltin
99
- if (id === 'uv') return 'gl_FragCoord.xy'
100
- }
101
- return id
112
+ return `var ${varName}: ${wgslType} = ${code(x, c)};`
102
113
  }
103
114
  return code(x, c)
104
115
  }
package/src/node/const.ts CHANGED
@@ -6,16 +6,16 @@ export const CONSTANTS = [
6
6
  'int',
7
7
  'float',
8
8
  'bvec2',
9
- 'bvec3',
10
- 'bvec4',
11
9
  'ivec2',
12
- 'ivec3',
13
- 'ivec4',
14
10
  'uvec2',
15
- 'uvec3',
16
- 'uvec4',
17
11
  'vec2',
12
+ 'bvec3',
13
+ 'ivec3',
14
+ 'uvec3',
18
15
  'vec3',
16
+ 'bvec4',
17
+ 'ivec4',
18
+ 'uvec4',
19
19
  'vec4',
20
20
  'color',
21
21
  'mat2',
@@ -24,26 +24,26 @@ export const CONSTANTS = [
24
24
  ] as const
25
25
 
26
26
  export const CONVERSIONS = [
27
- 'toFloat',
28
- 'toInt',
29
- 'toUint',
30
27
  'toBool',
31
- 'toVec2',
32
- 'toVec3',
33
- 'toVec4',
28
+ 'toUint',
29
+ 'toInt',
30
+ 'toFloat',
31
+ 'toBvec2',
34
32
  'toIvec2',
35
- 'toIvec3',
36
- 'toIvec4',
37
33
  'toUvec2',
38
- 'toUvec3',
39
- 'toUvec4',
40
- 'toBvec2',
34
+ 'toVec2',
41
35
  'toBvec3',
36
+ 'toIvec3',
37
+ 'toUvec3',
38
+ 'toVec3',
42
39
  'toBvec4',
40
+ 'toIvec4',
41
+ 'toUvec4',
42
+ 'toVec4',
43
+ 'toColor',
43
44
  'toMat2',
44
45
  'toMat3',
45
46
  'toMat4',
46
- 'toColor',
47
47
  ] as const
48
48
 
49
49
  export const OPERATORS = {
@@ -226,4 +226,5 @@ export const WGSL_TO_GLSL_BUILTIN = {
226
226
  sample_index: 'gl_SampleID',
227
227
  sample_mask: 'gl_SampleMask',
228
228
  point_coord: 'gl_PointCoord',
229
+ uv: 'gl_FragCoord.xy',
229
230
  } as const
package/src/node/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { conversion as c, function_ as f, node } from './node'
1
+ import { builtin, conversion as c, function_ as f, uniform } from './node'
2
2
  import { hex2rgb } from './utils'
3
3
  import { is } from '../utils/helpers'
4
4
  import type { X } from './types'
@@ -10,44 +10,25 @@ 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
-
23
- // Default uniforms
24
- export const iResolution = uniform([1280, 800], 'iResolution')
25
- export const iMouse = uniform([0, 0], 'iMouse')
26
- export const iTime = uniform(0, 'iTime')
27
-
28
13
  // 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' })
14
+ export const position = builtin('position')
15
+ export const vertexIndex = builtin('vertex_index')
16
+ export const instanceIndex = builtin('instance_index')
17
+ export const frontFacing = builtin('front_facing')
18
+ export const fragDepth = builtin('frag_depth')
19
+ export const sampleIndex = builtin('sample_index')
20
+ export const sampleMask = builtin('sample_mask')
21
+ export const pointCoord = builtin('point_coord')
37
22
 
38
23
  // TSL Compatible Builtin Variables
39
- export const positionLocal = node('builtin', { id: 'position' })
40
- export const positionWorld = node('builtin', { id: 'positionWorld' })
41
- export const positionView = node('builtin', { id: 'positionView' })
42
- export const normalLocal = node('builtin', { id: 'normalLocal' })
43
- export const normalWorld = node('builtin', { id: 'normalWorld' })
44
- export const normalView = node('builtin', { id: 'normalView' })
45
- export const screenCoordinate = node('builtin', { id: 'screenCoordinate' })
46
- export const screenUV = node('builtin', { id: 'screenUV' })
47
-
48
- // Legacy aliases for backward compatibility
49
- export const fragCoord = position
50
- export const vertexId = vertexIndex
24
+ export const normalLocal = builtin('normalLocal')
25
+ export const normalWorld = builtin('normalWorld')
26
+ export const normalView = builtin('normalView')
27
+ export const positionLocal = builtin('position')
28
+ export const positionWorld = builtin('positionWorld')
29
+ export const positionView = builtin('positionView')
30
+ export const screenCoordinate = builtin('screenCoordinate')
31
+ export const screenUV = builtin('screenUV')
51
32
 
52
33
  // Type constructors
53
34
  export const float = (x: X) => c('float', x)
@@ -74,6 +55,11 @@ export const color = (r?: X, g?: X, b?: X) => {
74
55
  return vec3(r, g, b)
75
56
  }
76
57
 
58
+ // Default uniforms
59
+ export const iResolution = uniform(vec2(1280, 800), 'iResolution')
60
+ export const iMouse = uniform(vec2(0, 0), 'iMouse')
61
+ export const iTime = uniform(float(0), 'iTime')
62
+
77
63
  // Texture Functions
78
64
  export const texture = (x: X, y: X, z?: X) => f('texture', x, y, z)
79
65
  export const cubeTexture = (x: X, y: X, z?: X) => f('cubeTexture', x, y, z)
package/src/node/infer.ts CHANGED
@@ -1,39 +1,21 @@
1
1
  import { is } from '../utils/helpers'
2
- import { isNodeProxy } from './utils'
3
2
  import {
4
- CONSTANTS,
5
- SCALAR_RETURN_FUNCTIONS,
6
3
  BOOL_RETURN_FUNCTIONS,
7
- PRESERVE_TYPE_FUNCTIONS,
8
- VEC3_RETURN_FUNCTIONS,
4
+ BUILTIN_TYPES,
5
+ COMPARISON_OPERATORS,
6
+ COMPONENT_COUNT_TO_TYPE,
7
+ CONSTANTS,
9
8
  FIRST_ARG_TYPE_FUNCTIONS,
10
9
  HIGHEST_TYPE_FUNCTIONS,
11
- VEC4_RETURN_FUNCTIONS,
12
- COMPARISON_OPERATORS,
13
10
  LOGICAL_OPERATORS,
14
- COMPONENT_COUNT_TO_TYPE,
15
- BUILTIN_TYPES,
11
+ PRESERVE_TYPE_FUNCTIONS,
12
+ SCALAR_RETURN_FUNCTIONS,
13
+ VEC3_RETURN_FUNCTIONS,
14
+ VEC4_RETURN_FUNCTIONS,
16
15
  } from './const'
16
+ import { isNodeProxy } from './utils'
17
17
  import type { Constants, NodeConfig, NodeProxy, X } from './types'
18
18
 
19
- const inferPrimitiveType = (x: any): Constants => {
20
- if (is.bol(x)) return 'bool'
21
- if (is.num(x)) return 'float' // Number.isInteger(x) ? 'int' : 'float' // @TODO FIX
22
- if (is.arr(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] || 'float'
23
- return 'float'
24
- }
25
-
26
- const inferBinaryOpType = (leftType: string, rightType: string, op: string): Constants => {
27
- if (COMPARISON_OPERATORS.includes(op as any)) return 'bool'
28
- if (LOGICAL_OPERATORS.includes(op as any)) return 'bool'
29
- if (leftType === rightType) return leftType as Constants
30
- if (leftType.includes('vec') && !rightType.includes('vec')) return leftType as Constants
31
- if (rightType.includes('vec') && !leftType.includes('vec')) return rightType as Constants
32
- const leftPriority = CONSTANTS.indexOf(leftType as any)
33
- const rightPriority = CONSTANTS.indexOf(rightType as any)
34
- return (leftPriority >= rightPriority ? leftType : rightType) as Constants
35
- }
36
-
37
19
  const getHighestPriorityType = (args: X[], c: NodeConfig) => {
38
20
  return args.reduce((highest, current) => {
39
21
  const currentType = infer(current, c)
@@ -43,15 +25,11 @@ const getHighestPriorityType = (args: X[], c: NodeConfig) => {
43
25
  }, 'float') as Constants
44
26
  }
45
27
 
46
- const inferSwizzleType = (count: number): Constants => {
47
- return COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE]!
48
- }
49
-
50
- const inferBuiltinType = (id: string | undefined): Constants => {
28
+ const inferBuiltin = (id: string | undefined): Constants => {
51
29
  return BUILTIN_TYPES[id as keyof typeof BUILTIN_TYPES]!
52
30
  }
53
31
 
54
- const inferMathType = (funcName: string, args: X[], c: NodeConfig): Constants => {
32
+ const inferFunction = (funcName: string, args: X[], c: NodeConfig): Constants => {
55
33
  const firstArgType = args.length > 0 ? infer(args[0], c) : 'float'
56
34
  if (FIRST_ARG_TYPE_FUNCTIONS.includes(funcName as any)) return firstArgType
57
35
  if (SCALAR_RETURN_FUNCTIONS.includes(funcName as any)) return 'float'
@@ -63,29 +41,47 @@ const inferMathType = (funcName: string, args: X[], c: NodeConfig): Constants =>
63
41
  return firstArgType
64
42
  }
65
43
 
44
+ const inferOperator = (leftType: string, rightType: string, op: string): Constants => {
45
+ if (COMPARISON_OPERATORS.includes(op as any)) return 'bool'
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
53
+ }
54
+
55
+ const inferPrimitiveType = (x: any): Constants => {
56
+ if (is.bol(x)) return 'bool'
57
+ if (is.num(x)) return 'float' // Number.isInteger(x) ? 'int' : 'float' // @TODO FIX
58
+ if (is.arr(x)) return COMPONENT_COUNT_TO_TYPE[x.length as keyof typeof COMPONENT_COUNT_TO_TYPE] || 'float'
59
+ return 'float'
60
+ }
61
+
62
+ const inferSwizzle = (count: number): Constants => {
63
+ return COMPONENT_COUNT_TO_TYPE[count as keyof typeof COMPONENT_COUNT_TO_TYPE]!
64
+ }
65
+
66
66
  export const inferImpl = (target: NodeProxy, c: NodeConfig): Constants => {
67
67
  const { type, props } = target
68
- const { id, children = [], value } = props
68
+ const { id, children = [], inferFrom } = props
69
69
  const [x, y, z] = children
70
- if (
71
- type === 'uniform' ||
72
- type === 'variable' ||
73
- type === 'constant' ||
74
- type === 'attribute' ||
75
- type === 'varying'
76
- )
77
- return inferPrimitiveType(value)
70
+ if (inferFrom) return infer(inferFrom, c)
78
71
  if (type === 'conversion') return x as Constants
79
- if (type === 'operator') return inferBinaryOpType(infer(y, c), infer(z, c), x as string)
80
- if (type === 'function') return inferMathType(x as string, children.slice(1), c)
81
- if (type === 'swizzle') return inferSwizzleType((x as string).length)
82
- if (type === 'ternary') return inferBinaryOpType(infer(y, c), infer(z, c), 'add')
83
- if (type === 'define') return y ? infer(y, c) : 'void'
84
- if (type === 'builtin') return inferBuiltinType(id)
85
- return 'float'
72
+ if (type === 'operator') return inferOperator(infer(y, c), infer(z, c), x as string)
73
+ if (type === 'function') return inferFunction(x as string, children.slice(1), c)
74
+ if (type === 'swizzle') return inferSwizzle((x as string).length)
75
+ if (type === 'ternary') return inferOperator(infer(y, c), infer(z, c), 'add')
76
+ if (type === 'builtin') return inferBuiltin(id)
77
+ if (type === 'define') {
78
+ if (props.layout?.type && props.layout?.type !== 'auto') return props.layout.type as Constants
79
+ return y ? infer(y, c) : 'void'
80
+ }
81
+ return infer(x, c)
86
82
  }
87
83
 
88
- export const infer = (target: X, c: NodeConfig | null): Constants => {
84
+ export const infer = (target: X, c?: NodeConfig | null): Constants => {
89
85
  if (!c) c = {}
90
86
  if (!isNodeProxy(target)) return inferPrimitiveType(target)
91
87
  if (!c.infers) c.infers = new WeakMap<NodeProxy, Constants>()
package/src/node/node.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { code } from './code'
2
2
  import { assign, toVar } from './scope'
3
- import { getId, isConversion, isFunction, isOperator, isSwizzle } from './utils'
3
+ import { conversionToConstant, isConversion, isFunction, isOperator, isSwizzle } from './utils'
4
4
  import type { Functions, NodeProps, NodeProxy, NodeTypes, Operators, Swizzles, X } from './types'
5
5
 
6
6
  const toPrimitive = (x: X, hint: string) => {
@@ -21,11 +21,11 @@ export const node = (type: NodeTypes, props?: NodeProps | null, ...args: X[]) =>
21
21
  if (isSwizzle(key)) return swizzle(key, x)
22
22
  if (isOperator(key)) return (...y: X[]) => operator(key, x, ...y)
23
23
  if (isFunction(key)) return (...y: X[]) => function_(key, x, ...y)
24
- if (isConversion(key)) return conversion(key, x)
24
+ if (isConversion(key)) return () => conversion(conversionToConstant(key), x)
25
25
  }
26
- const set = (_: unknown, key: string, value: X) => {
26
+ const set = (_: unknown, key: string, y: X) => {
27
27
  if (isSwizzle(key)) {
28
- swizzle(key, x).assign(value)
28
+ swizzle(key, x).assign(y)
29
29
  return true
30
30
  }
31
31
  return false
@@ -34,9 +34,19 @@ export const node = (type: NodeTypes, props?: NodeProps | null, ...args: X[]) =>
34
34
  return x
35
35
  }
36
36
 
37
+ // headers
38
+ export const attribute = (x: X, id?: string) => node('varying', { id }, x)
39
+ export const uniform = (x: X, id?: string) => node('uniform', { id }, x)
40
+ export const varying = (x: X, id?: string) => node('varying', { id }, x)
41
+ export const constant = (x: X, id?: string) => node('constant', { id }, x)
42
+ export const variable = (id: string) => node('variable', { id })
43
+ export const builtin = (id: string) => node('builtin', { id })
44
+
37
45
  // Node shorthands
38
- export const variable = (...args: X[]) => node('variable', { id: getId() }, ...args)
39
46
  export const swizzle = (key: Swizzles, arg: X) => node('swizzle', null, key, arg)
40
47
  export const operator = (key: Operators, ...args: X[]) => node('operator', null, key, ...args)
41
48
  export const function_ = (key: Functions, ...args: X[]) => node('function', null, key, ...args)
42
49
  export const conversion = (key: string, ...args: X[]) => node('conversion', null, key, ...args)
50
+
51
+ // x ? y : z
52
+ export const select = (x: X, y: X, z: X) => node('ternary', null, x, y, z)
package/src/node/scope.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { node } from './node'
1
+ import { int } from '.'
2
+ import { conversion, node } from './node'
2
3
  import { getId } from './utils'
3
- import type { NodeProxy, X } from './types'
4
+ import type { FnLayout, NodeProps, NodeProxy, X } from './types'
4
5
 
5
6
  let _scope: NodeProxy | null = null
6
7
 
@@ -19,8 +20,8 @@ const addToScope = (x: NodeProxy) => {
19
20
 
20
21
  export const toVar = (x: X, id?: string) => {
21
22
  if (!id) id = getId()
22
- const y = node('variable', { id })
23
- const z = node('declare', null, y, x)
23
+ const y = node('variable', { id, inferFrom: x })
24
+ const z = node('declare', null, x, y)
24
25
  addToScope(z)
25
26
  return y
26
27
  }
@@ -31,48 +32,45 @@ export const assign = (x: X, y: X) => {
31
32
  return x
32
33
  }
33
34
 
34
- export const If = (condition: X, fun: () => void) => {
35
- const scope = node('scope')
36
- scoped(scope, fun)
37
- const ifNode = node('if', null, condition, scope)
35
+ export const If = (x: X, fun: () => void) => {
36
+ const y = node('scope')
37
+ scoped(y, fun)
38
+ const ifNode = node('if', null, x, y)
38
39
  addToScope(ifNode)
39
- const createChain = () => ({
40
- ElseIf: (x: X, _fun: () => void) => {
41
- const y = node('scope')
42
- scoped(y, _fun)
43
- ifNode.props.children!.push(x, y)
44
- return createChain()
40
+ const ret = () => ({
41
+ ElseIf: (_x: X, _fun: () => void) => {
42
+ const _y = node('scope')
43
+ scoped(_y, _fun)
44
+ ifNode.props.children!.push(_x, _y)
45
+ return ret()
45
46
  },
46
47
  Else: (_fun: () => void) => {
47
- const x = node('scope')
48
- scoped(x, _fun)
49
- ifNode.props.children!.push(x)
48
+ const _x = node('scope')
49
+ scoped(_x, _fun)
50
+ ifNode.props.children!.push(_x)
50
51
  },
51
52
  })
52
- return createChain()
53
+ return ret()
53
54
  }
54
55
 
55
- export const Loop = (x: X, fun: (params: { i?: NodeProxy }) => void) => {
56
+ export const Loop = (x: X, fun: (params: { i: NodeProxy }) => void) => {
56
57
  const y = node('scope')
57
- scoped(y, () => fun({ i: node('variable', { id: 'i' }) }))
58
+ scoped(y, () => fun({ i: node('variable', { id: 'i', inferFrom: int(0) }) }))
58
59
  const ret = node('loop', null, x, y)
59
60
  addToScope(ret)
60
61
  return ret
61
62
  }
62
63
 
63
- export const Switch = (value: X) => {
64
- const switchNode = node('switch', null, value)
64
+ export const Switch = (x: X) => {
65
+ const switchNode = node('switch', null, x)
65
66
  addToScope(switchNode)
66
- const createChain = () => ({
67
+ const ret = () => ({
67
68
  Case: (...values: X[]) => {
68
69
  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
- }
75
- return createChain()
70
+ const y = node('scope')
71
+ scoped(y, fun)
72
+ for (const _x of values) switchNode.props.children!.push(_x, y)
73
+ return ret()
76
74
  }
77
75
  },
78
76
  Default: (fun: () => void) => {
@@ -82,21 +80,32 @@ export const Switch = (value: X) => {
82
80
  },
83
81
  })
84
82
 
85
- return createChain()
83
+ return ret()
86
84
  }
87
85
 
88
86
  export const Fn = (fun: (paramVars: NodeProxy[]) => NodeProxy) => {
89
- const id = getId()
90
- return (...args: X[]) => {
87
+ let layout: FnLayout
88
+ const ret = (...args: X[]) => {
89
+ const id = layout?.name || getId()
91
90
  const x = node('scope')
92
91
  let y: NodeProxy | undefined
93
92
  const paramVars: NodeProxy[] = []
94
- for (let i = 0; i < args.length; i++) {
95
- const paramId = `p${i}`
96
- const paramVar = node('variable', { id: paramId })
97
- paramVars.push(paramVar)
98
- }
93
+ const paramDefs: NodeProps[] = []
94
+ if (layout?.inputs)
95
+ for (const input of layout.inputs) {
96
+ paramDefs.push({ id: input.name, inferFrom: conversion(input.type) })
97
+ }
98
+ else
99
+ for (let i = 0; i < args.length; i++) {
100
+ paramDefs.push({ id: `p${i}`, inferFrom: args[i] })
101
+ }
102
+ for (const props of paramDefs) paramVars.push(node('variable', props))
99
103
  scoped(x, () => (y = fun(paramVars)))
100
- return node('define', { id }, x, y, ...args)
104
+ return node('define', { id, layout }, x, y, ...args)
101
105
  }
106
+ ret.setLayout = (newLayout: FnLayout) => {
107
+ layout = newLayout
108
+ return ret
109
+ }
110
+ return ret
102
111
  }