furnace-xray 1.1.0.pre1 → 1.1.0.pre2

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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/lib/furnace-xray/app/assets/javascripts/application.js.coffee +9 -9
  3. data/lib/furnace-xray/app/assets/javascripts/lib/graph.js.coffee +6 -5
  4. data/lib/furnace-xray/app/assets/javascripts/lib/input.js.coffee +43 -104
  5. data/lib/furnace-xray/app/assets/javascripts/lib/input_state.js.coffee +6 -4
  6. data/lib/furnace-xray/app/assets/javascripts/lib/node.js.coffee +39 -0
  7. data/lib/furnace-xray/app/assets/javascripts/lib/nodes/argument.js.coffee +9 -2
  8. data/lib/furnace-xray/app/assets/javascripts/lib/nodes/basic_block.js.coffee +82 -0
  9. data/lib/furnace-xray/app/assets/javascripts/lib/nodes/constant.js.coffee +9 -0
  10. data/lib/furnace-xray/app/assets/javascripts/lib/nodes/function.js.coffee +20 -5
  11. data/lib/furnace-xray/app/assets/javascripts/lib/nodes/instruction.js.coffee +43 -23
  12. data/lib/furnace-xray/app/assets/javascripts/lib/nodes/module.js.coffee +8 -0
  13. data/lib/furnace-xray/app/assets/javascripts/lib/nodes/phi.js.coffee +10 -0
  14. data/lib/furnace-xray/app/assets/javascripts/lib/nodes/type.js.coffee +6 -9
  15. data/lib/furnace-xray/app/assets/javascripts/lib/nodes/type_bottom.js.coffee +3 -0
  16. data/lib/furnace-xray/app/assets/javascripts/lib/nodes/type_variable.js.coffee +1 -0
  17. data/lib/furnace-xray/app/views/nodes/{instruction_typed.jst.mustache → instruction.jst.mustache} +0 -0
  18. data/lib/furnace-xray/app/views/nodes/{operand_argument.jst.mustache → operands/argument.jst.mustache} +0 -0
  19. data/lib/furnace-xray/app/views/nodes/{operand_basic_block.jst.mustache → operands/basic_block.jst.mustache} +0 -0
  20. data/lib/furnace-xray/app/views/nodes/{operand_constant.jst.mustache → operands/constant.jst.mustache} +0 -0
  21. data/lib/furnace-xray/app/views/nodes/{operand_instruction.jst.mustache → operands/instruction.jst.mustache} +0 -0
  22. data/lib/furnace-xray/app/views/nodes/{type_constant.jst.mustache → type.jst.mustache} +0 -0
  23. data/lib/furnace-xray/version.rb +1 -1
  24. data/sample.json +8909 -1
  25. metadata +15 -13
  26. data/lib/furnace-xray/app/assets/javascripts/lib/map.js.coffee +0 -48
  27. data/lib/furnace-xray/app/assets/javascripts/lib/nodes/block.js.coffee +0 -76
  28. data/lib/furnace-xray/app/assets/javascripts/lib/nodes/operand.js.coffee +0 -21
  29. data/lib/furnace-xray/app/views/nodes/operand_constant_function.jst.mustache +0 -1
  30. data/lib/furnace-xray/app/views/nodes/type_parametric.jst.mustache +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad3fbcd1c6346fa30c03fa890bd356da8440d602
4
- data.tar.gz: ab2c38eee0ee6edaff32064341037e61874bb34f
3
+ metadata.gz: c33b7ac042d318fbb36bc37effca9374300eff92
4
+ data.tar.gz: 126063f60ad1f161a7d3f8b093dbdf78a6637e94
5
5
  SHA512:
6
- metadata.gz: 2b18eba9f93d570ddc9f9c40a4fead4b045c46088354666248b1eb87aa1ef835e3b919a030b5f59248a7b183703284f69b0c13b27a563181eb06b0c0bacb081d
7
- data.tar.gz: b9cfcca32473c06a899459259a602028b322ed9db8c30ce43aea2a8d8697c3e63fa3b832d7d64679828dd0f5ba71ed2f329037c7df7d4fb656791853a732d4ed
6
+ metadata.gz: 14b818259d317c73fe046ef38ed131dbc24cd32430c4afdb2413f4100f90f76c7a12c0e7d418066caba2018ad396791fc0ea548b995f2bfae4502af630c1bf7c
7
+ data.tar.gz: aa33c93878d6d0a011c4640526c949114d89768bc0d9a631e2a145429047722924ebcade79660fb13028628e90d133c39e8ab23c464e123a361c4113d69bd5b7
@@ -64,16 +64,16 @@ class Application
64
64
  @transform.removeClass('active').html('')
65
65
  @diff.html('')
66
66
 
67
- input = @data[@currentFunction]
67
+ input = Input.functions[@currentFunction].input
68
68
 
69
- Drawer.reset() if @input?.source.name != input.source.name
69
+ Drawer.reset() if @input?.function.name != input.function.name
70
70
  Drawer.clear()
71
71
 
72
72
  @input = input
73
73
  @input.rewind(@currentStep)
74
74
  @drawer = new Drawer(new Graph(@input))
75
75
 
76
- @title.html @input.function.title()
76
+ @title.html @input.map[@input.function.id]?.title()
77
77
  @diff.html "~ " + @input.previousState.cursor if @input.previousState?.cursor?
78
78
 
79
79
  @renewZoomer()
@@ -87,7 +87,7 @@ class Application
87
87
 
88
88
  dehasherize: ->
89
89
  hash = window.location.hash.from(1)
90
- hash = "0:#{@data[0].events.length-1}" if hash.length == 0
90
+ hash = "0:#{Input.functions[0].input.events.length-1}" if hash.length == 0
91
91
  [@currentFunction, @currentStep] = hash.split(":").map (x) -> x.toNumber()
92
92
 
93
93
  jumpTo: (func, step) ->
@@ -95,8 +95,8 @@ class Application
95
95
  @selector.find('option').each (x) ->
96
96
  func = $(@).attr('value').toNumber() if $(@).text() == func
97
97
 
98
- @currentFunction = func; step = @data[func].events.length-1 if step == undefined
99
- @currentStep = [step, @data[func].events.length-1].min()
98
+ @currentFunction = func; step = Input.functions[func].input.events.length-1 if step == undefined
99
+ @currentStep = [step, Input.functions[func].input.events.length-1].min()
100
100
  @currentStep = [0, @currentStep].max()
101
101
  window.location.hash = "#{@currentFunction}:#{@currentStep || 0}"
102
102
 
@@ -162,9 +162,9 @@ class Application
162
162
  buildSelector: ->
163
163
  groups = ['Present', 'Removed'].map (x) -> $("<optgroup label='#{x}'></optgroup>")
164
164
 
165
- @data.each (f, i) =>
166
- group = if f.source.present then groups[0] else groups[1]
167
- group.append "<option value='#{i}'>#{f.source.name}</option>"
165
+ Input.functions.each (f, i) ->
166
+ group = if f.present then groups[0] else groups[1]
167
+ group.append "<option value='#{i}'>#{f.name}</option>"
168
168
 
169
169
  groups.each (x) => @selector.append x
170
170
 
@@ -8,18 +8,19 @@ class @Graph
8
8
  @edges = []
9
9
  blockNodes = Object.extended()
10
10
 
11
- @input.blocks.each (i, b) =>
12
- blockNodes[b.name] =
11
+ @input.activeBlocks()?.each (b) =>
12
+ blockNodes[b.id] =
13
13
  edges: b.references()
14
14
  label: b.name
15
- data: b.title(@input.previousState?.blocks[b.name])
15
+ data: b.title(unless @input.previousState? then false else (@input.previousState.basicBlocks[b.id] || []))
16
16
 
17
17
  blockNodes.each (i, n) =>
18
18
  edges = []
19
19
 
20
20
  n.edges.each (x) =>
21
- edges.add {source: n, target: blockNodes[x], data: blockNodes[x].label}
22
- @edges.add edges.last()
21
+ if blockNodes[x]?
22
+ edges.add {source: n, target: blockNodes[x], data: blockNodes[x].label}
23
+ @edges.add edges.last()
23
24
 
24
25
  n.edges = edges
25
26
 
@@ -2,61 +2,63 @@
2
2
  # Internal representation of input JSON
3
3
  #
4
4
  class @Input
5
- @normalize: (data) ->
6
- data.map (x) -> new Input(x)
7
-
8
- constructor: (@source) ->
9
- @source.events.each (x) -> x.event = x.event.camelize(false)
10
-
11
- # Scan for effective events
12
- @events = []
13
- reducer = []
5
+ @normalize: (@events) =>
6
+ @functions = []
7
+ events = Object.extended()
14
8
  transforms = Object.extended()
15
9
 
16
- @source.events.each (x, i) =>
17
- switch x.event
18
- when 'addInstruction'
19
- reducer.add x.name
20
- @events.add i
21
- when 'removeInstruction'
22
- reducer.exclude x.name
23
- @events.add i
24
- when 'updateInstruction', 'renameInstruction'
25
- @events.add i if reducer.any(x.name)
26
- when 'type', 'transformStart'
27
- else
28
- @events.add i
29
-
30
- if x.event == 'transformStart'
31
- id = @events.length-1
32
- transforms[id] = {id: id, label: x.name}
33
-
34
- @transforms = transforms.values()
10
+ @events.each (event, i) =>
11
+ if event['kind'] == 'transform'
12
+ f = event['function_id']
13
+
14
+ transforms[f] ||= []
15
+ transforms[f].push
16
+ id: events[f].length - 1
17
+ label: event['name']
18
+ else
19
+ node = Node.refresh(event)
20
+
21
+ if node.attachedFunctions?
22
+ Object.each node.attachedFunctions(), (id, f) =>
23
+ events[id] ||= []
24
+ events[id].push i
25
+
26
+ Node.kinds['function'].each (f) =>
27
+ @functions.push
28
+ name: f.name
29
+ present: f.present
30
+ input: new Input(f, events[f.id], transforms[f.id])
31
+
32
+ @constantize: (kind) ->
33
+ result = window[kind.camelize()+'Node']
34
+ result
35
+
36
+ constructor: (@function, @events, @transforms) ->
35
37
  @transforms = @transforms.filter (x, i) =>
36
38
  x.length = (@transforms[i+1]?.id || @events.length) - x.id
37
- x.id < @events.length-1
39
+ x.id < @events.length-1 && x.length > 0
38
40
 
39
41
  @reset()
40
42
 
41
- reset: ->
42
- @types = Object.extended()
43
- @blocks = Object.extended()
44
- @instructions = Object.extended()
45
- @blocksMap = new Map 'blocks'
46
- @instructionsMap = new Map 'instructions'
43
+ activeBlocks: ->
44
+ data = @kinds['basic_block']?.findAll (b) =>
45
+ b.attachedFunctions()[@function.id]?
47
46
 
48
- @function = new FunctionNode(@source.name, @source.present)
49
- @cursor = 0
47
+ data || []
50
48
 
51
- # run first step at initialization
52
- i = -1; @run(i) while (i+=1) <= (@events[1] || @source.events.length-1)
49
+ reset: ->
50
+ @map = Object.extended()
51
+ @kinds = Object.extended()
52
+ @cursor = 0
53
+
54
+ # run upcoming steps at initialization
55
+ i = -1; @run(i) while (i+=1) < @events[0]
53
56
 
54
57
  rewind: (to) ->
55
58
  return if to == @cursor
56
59
 
57
60
  if to < @cursor
58
61
  delete @previousState
59
- @reset()
60
62
  else
61
63
  @previousState = new InputState(@)
62
64
 
@@ -72,67 +74,4 @@ class @Input
72
74
  @cursor = stop
73
75
 
74
76
  run: (step) ->
75
- event = @source.events[step]
76
-
77
- if event.event == 'type'
78
- @types[event.id] = new TypeNode(event.kind, event.name, event.parameters)
79
- else
80
- @[event.event]?(event)
81
- console.log "UNKNOWN EVENT: #{event.event}" unless @[event.event]?
82
-
83
- type: (id) ->
84
- return undefined unless id?
85
-
86
- if type = @types[id]
87
- return type
88
- else
89
- @reset()
90
- throw "Type #{id} not found in #{@types.keys().join(',')}"
91
-
92
- setReturnType: (event) ->
93
- @function.setReturnType @type(event.return_type)
94
-
95
- setArguments: (event) ->
96
- @function.setArguments(event.arguments.map (x) =>
97
- new ArgumentNode(x.name, @type(x.type)))
98
-
99
- addBasicBlock: (event) ->
100
- @blocksMap.add event.name, (id) =>
101
- @blocks[id] = new BlockNode(event.name)
102
-
103
- removeBasicBlock: (event) ->
104
- @blocksMap.remove event.name, (id) =>
105
- delete @blocks[id]
106
-
107
- renameBasicBlock: (event) ->
108
- @blocksMap.rename event.name, event.new_name, (id) =>
109
- @blocks[id].setName(event.new_name)
110
-
111
- updateInstruction: (event) ->
112
- id = @instructionsMap.add event.name, (id) =>
113
- @instructions[id] = new InstructionNode
114
-
115
- if Object.isArray(event.operands)
116
- operands = event.operands.map (x) =>
117
- new OperandNode x.kind, @type(x.type), x.name, x.value
118
- else
119
- operands = []
120
- Object.each event.operands, (key, x) =>
121
- operands.push [key, new OperandNode(x.kind, @type(x.type), x.name, x.value)]
122
-
123
- @instructions[id].update event.opcode, event.name, event.parameters, operands, @type(event.type)
124
-
125
- addInstruction: (event) ->
126
- @instructionsMap.locateOrAdd event.name, (i) =>
127
- @blocksMap.locate event.basic_block, (b) =>
128
- @instructions[i].link @blocks[b], event.index
129
-
130
- removeInstruction: (event) ->
131
- @instructionsMap.locate event.name, (i) =>
132
- @instructions[i].unlink()
133
-
134
- renameInstruction: (event) ->
135
- @instructionsMap.rename event.name, event.new_name, (i) =>
136
- @instructions[i].name = event.new_name
137
-
138
- transformStart: (event) ->
77
+ node = Node.refresh(Input.events[step], @map, @kinds)
@@ -1,8 +1,10 @@
1
1
  class @InputState
2
2
  constructor: (input) ->
3
- @blocks = Object.extended()
3
+ @basicBlocks = Object.extended()
4
4
  @cursor = input.cursor
5
5
 
6
- input.blocksMap.each (bname, id) =>
7
- @blocks[bname] = input.blocks[id].instructions.map (x) ->
8
- {title: x.title(), name: x.name}
6
+ input.kinds['basic_block']?.each (b) =>
7
+ @basicBlocks[b.id] = b.instructions.map (i) =>
8
+ id: i.id
9
+ name: i.name
10
+ title: i.title()
@@ -0,0 +1,39 @@
1
+ class @Node
2
+ @refresh: (data, map=false, kinds=false) ->
3
+ Node.map ||= Object.extended()
4
+ Node.kinds ||= Object.extended()
5
+
6
+ map ||= Node.map
7
+ kinds ||= Node.kinds
8
+
9
+ if map[data.id]
10
+ map[data.id].update(data, map)
11
+ else
12
+ klass = window[data.kind.camelize()+'Node']
13
+
14
+ return false if !klass?
15
+
16
+ kinds[data.kind] ||= []
17
+ kinds[data.kind].push map[data.id] = new klass(data, map)
18
+
19
+ map[data.id]
20
+
21
+ @reset: ->
22
+ Node.map = Object.extended()
23
+ Node.kinds = {}
24
+
25
+ constructor: (data, map) ->
26
+ @id = data.id
27
+ @update(data, map)
28
+
29
+ update: (data, map) ->
30
+
31
+ locate: (id, map) ->
32
+ map[id] || throw("Element #{id} not found in map")
33
+
34
+ reassign: (before, after, callback) ->
35
+ if !before? || before.length == 0
36
+ callback([], after)
37
+ else
38
+ intersection = before.intersect(after)
39
+ callback before.subtract(intersection), after.subtract(intersection)
@@ -1,7 +1,14 @@
1
- class @ArgumentNode
2
- constructor: (@name, @type) ->
1
+ class @ArgumentNode extends Node
2
+ update: (data, map) ->
3
+ @name = data['name']
4
+ @type = @locate(data['type'], map)
3
5
 
4
6
  title: ->
5
7
  JST['nodes/argument']
8
+ type: @type.title()
9
+ name: @name
10
+
11
+ operandTitle: ->
12
+ JST['nodes/operands/argument']
6
13
  type: @type.title()
7
14
  name: @name
@@ -0,0 +1,82 @@
1
+ class @BasicBlockNode extends Node
2
+ constructor: (data, map) ->
3
+ super
4
+ @functions = Object.extended()
5
+
6
+ update: (data, map) ->
7
+ @name = data['name']
8
+
9
+ @reassign @instructionIds, data['instruction_ids'], (removed, added) =>
10
+ removed.each (id) => @locate(id, map).unlinkBlock(@)
11
+ added.each (id) => @locate(id, map).linkBlock(@)
12
+
13
+ @instructionIds = data['instruction_ids']
14
+ @instructions = @instructionIds.map (id) => @locate(id, map)
15
+
16
+ linkFunction: (f) ->
17
+ @functions[f.id] = f
18
+
19
+ unlinkFunction: (f) ->
20
+ delete @functions[f.id]
21
+
22
+ attachedFunctions: -> @functions
23
+
24
+ title: (previousInstructions) ->
25
+ JST['nodes/block']
26
+ name: @name
27
+ instructions: @titleizeInstructions(previousInstructions)
28
+
29
+ operandTitle: ->
30
+ JST['nodes/operands/basic_block']
31
+ name: @name
32
+
33
+ titleizeInstructions: (previousInstructions) ->
34
+ unless previousInstructions
35
+ result = ""
36
+ result += JST['nodes/diff/unchanged_line'] line: x.title() for x in @instructions
37
+ result
38
+ else
39
+ result = ""
40
+ removed = Object.extended()
41
+ added = Object.extended()
42
+ changed = Object.extended()
43
+ unchanged = Object.extended()
44
+
45
+ for cs, i in @instructions
46
+ previous = previousInstructions.find (ps) -> ps.id == cs.id
47
+ currentTitle = cs.title()
48
+
49
+ if previous && previous.title == currentTitle
50
+ unchanged[i] = previous.title
51
+ previous.newPosition = i
52
+ else if previous
53
+ changed[i] = [previous.title, currentTitle]
54
+ previous.newPosition = i
55
+ else
56
+ added[i] = currentTitle
57
+
58
+ for ps, i in previousInstructions
59
+ if !ps.newPosition?
60
+ position = 0
61
+
62
+ while --i >= 0
63
+ if previousInstructions[i].newPosition?
64
+ position = previousInstructions[i].newPosition+1
65
+ break
66
+
67
+ removed[position] ||= []
68
+ removed[position].push ps.title
69
+
70
+ [@instructions.length, previousInstructions.length].max().times (i) ->
71
+ if removed[i]
72
+ result += JST['nodes/diff/removed_line'](line: l) for l in removed[i]
73
+
74
+ result += JST['nodes/diff/added_line'](line: added[i]) if added[i]
75
+ result += JST['nodes/diff/changed_line'](before: changed[i][0], after:changed[i][1]) if changed[i]
76
+ result += JST['nodes/diff/unchanged_line'](line: unchanged[i]) if unchanged[i]
77
+
78
+ result
79
+
80
+ references: ->
81
+ ids = @instructions.last()?.operands.findAll((x) -> x instanceof BasicBlockNode).map((x) -> x.id)
82
+ (ids || []).exclude((x) => x == @id)
@@ -0,0 +1,9 @@
1
+ class @ConstantNode extends Node
2
+ update: (data, map) ->
3
+ @value = data['value']
4
+ @type = @locate(data['type'], map)
5
+
6
+ operandTitle: ->
7
+ JST['nodes/operands/constant']
8
+ type: @type.title()
9
+ value: @value
@@ -1,10 +1,25 @@
1
- class @FunctionNode
2
- constructor: (@name, @present) ->
3
- @arguments = []
1
+ class @FunctionNode extends Node
2
+ update: (data, map) ->
3
+ @name = data['name']
4
+ @type = @locate(data['return_type'], map)
5
+ @present = false
4
6
 
5
- setArguments: (@arguments) ->
7
+ @arguments = data['argument_ids'].map (id) => @locate(id, map)
6
8
 
7
- setReturnType: (@type) ->
9
+ @reassign @blockIds, data['basic_block_ids'], (removed, added) =>
10
+ removed.each (id) => @locate(id, map).unlinkFunction(@)
11
+ added.each (id) => @locate(id, map).linkFunction(@)
12
+
13
+ @blockIds = data['basic_block_ids']
14
+ @blocks = @blockIds.map (id) => @locate(id, map)
15
+
16
+ linkModule: -> @present = true
17
+ unlinkModule: -> @present = false
18
+
19
+ attachedFunctions: ->
20
+ result = {}
21
+ result[@id] = @
22
+ result
8
23
 
9
24
  title: ->
10
25
  template = if @present then 'nodes/function' else 'nodes/function_removed'
@@ -1,33 +1,53 @@
1
- class @InstructionNode
2
- constructor: ->
3
- @blocks = []
1
+ class @InstructionNode extends Node
2
+ constructor: (data, map) ->
3
+ super
4
+ @blocks = Object.extended()
4
5
 
5
- update: (@opcode, @name, @parameters, @operands, @type) ->
6
+ linkBlock: (block) ->
7
+ @blocks[block.id] = block
8
+ @operands?.each (x) => x.linkBlock(block) if x['linkBlock']?
6
9
 
7
- link: (block, index) ->
8
- block.addInstruction(@, index)
9
- @blocks.add block
10
+ unlinkBlock: (block) ->
11
+ delete @blocks[block.id]
12
+ @operands?.each (x) => x.unlinkBlock(block) if x['unlinkBlock']?
10
13
 
11
- unlink: ->
12
- @blocks.each (x) => x.removeInstruction(@)
13
- @blocks = []
14
+ attachedFunctions: ->
15
+ result = {}
16
+ @blocks.values().each (x) -> Object.merge result, x.attachedFunctions()
17
+ result
14
18
 
15
- title: ->
16
- operands = @operands.map (x) ->
17
- if x instanceof OperandNode
18
- x.title()
19
- else
20
- "%#{x[0]} => #{x[1].title()}"
19
+ update: (data, map) ->
20
+ @type = @locate(data['type'], map)
21
+ @name = data['name']
22
+ @opcode = data['opcode']
23
+ @parameters = data['parameters']
21
24
 
22
- if @type.kind == 'void'
23
- JST['nodes/instruction_void']
24
- opcode: @opcode
25
- parameters: @parameters
26
- operands: operands.join(', ')
25
+ if data['operand_ids']
26
+ @updateOperands(data['operand_ids'], map)
27
27
  else
28
- JST['nodes/instruction_typed']
28
+ @operands = null
29
+
30
+ updateOperands: (data, map) ->
31
+ @operands = data.map (x) => @locate(x, map)
32
+
33
+ title: ->
34
+ if @type && !@type.void()
35
+ JST['nodes/instruction']
29
36
  type: @type.title()
30
37
  name: @name
31
38
  opcode: @opcode
32
39
  parameters: @parameters
33
- operands: operands.join(', ')
40
+ operands: @titleizeOperands()
41
+ else
42
+ JST['nodes/instruction_void']
43
+ opcode: @opcode
44
+ parameters: @parameters
45
+ operands: @titleizeOperands()
46
+
47
+ titleizeOperands: ->
48
+ return "<DETACHED>" unless @operands
49
+ @operands.map((x) -> x.operandTitle()).join(', ')
50
+
51
+ operandTitle: ->
52
+ JST['nodes/operands/instruction']
53
+ name: @name
@@ -0,0 +1,8 @@
1
+ class @ModuleNode extends Node
2
+ update: (data, map) ->
3
+ @reassign @functionIds, data['function_ids'], (removed, added) =>
4
+ removed.each (id) => @locate(id, map).unlinkModule(@)
5
+ added.each (id) => @locate(id, map).linkModule(@)
6
+
7
+ @functionIds = data['function_ids']
8
+ @functions = @functionIds.map (id) => @locate(id, map)
@@ -0,0 +1,10 @@
1
+ class @PhiNode extends InstructionNode
2
+
3
+ updateOperands: (data, map) ->
4
+ @operands = data.map (pair) =>
5
+ pair.map (x) =>
6
+ @locate(x, map)
7
+
8
+ titleizeOperands: (data) ->
9
+ return "<DETACHED>" unless @operands
10
+ @operands.map (pair) => "#{pair[0].operandTitle()} => #{pair[1].operandTitle()}"
@@ -1,12 +1,9 @@
1
- class @TypeNode
1
+ class @TypeNode extends Node
2
2
 
3
- constructor: (@kind, @name, @parameters) ->
3
+ update: (data, map) ->
4
+ @name = data['name']
5
+
6
+ void: () -> false
4
7
 
5
8
  title: ->
6
- switch @kind
7
- when 'void' then JST['nodes/type_constant'](type: 'void')
8
- when 'monotype' then JST['nodes/type_constant'](type: @name)
9
- when 'parametric'
10
- JST['nodes/type_parametric']
11
- type: @name
12
- parameters: @parameters.map((x) -> x.title()).join(', ')
9
+ JST['nodes/type'](type: @name)
@@ -0,0 +1,3 @@
1
+ class @TypeBottomNode extends TypeNode
2
+
3
+ void: () -> true
@@ -0,0 +1 @@
1
+ class @TypeVariableNode extends @TypeNode
@@ -1,5 +1,5 @@
1
1
  module Furnace
2
2
  module Xray
3
- VERSION = '1.1.0.pre1'
3
+ VERSION = '1.1.0.pre2'
4
4
  end
5
5
  end