CCS.coffee 42.7 KB
Newer Older
Sebastian Biewer's avatar
Sebastian Biewer committed
1
###
2
3
4
5
PseuCo Compiler  
Copyright (C) 2013  
Saarland University (www.uni-saarland.de)  
Sebastian Biewer (biewer@splodge.com)
Sebastian Biewer's avatar
Sebastian Biewer committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
###
Sebastian Biewer's avatar
Sebastian Biewer committed
20

Sebastian Biewer's avatar
Sebastian Biewer committed
21
# - Constants
Sebastian Biewer's avatar
Sebastian Biewer committed
22
CCSInternalChannel = "\u03c4"	# tau
Sebastian Biewer's avatar
Sebastian Biewer committed
23
CCSExitChannel = "\u03b4"		# rho	
Sebastian Biewer's avatar
Sebastian Biewer committed
24
CCSUIChannel = "\u03c8"			# psi		# remove?
Sebastian Biewer's avatar
Sebastian Biewer committed
25
26
ObjID = 1
_DEBUG = []
Sebastian Biewer's avatar
Sebastian Biewer committed
27

Sebastian Biewer's avatar
Sebastian Biewer committed
28
DSteps = []
Sebastian Biewer's avatar
Sebastian Biewer committed
29
DS = ->			# remove?
Sebastian Biewer's avatar
Sebastian Biewer committed
30
31
32
33
	console.log ccs.system.toString()
	DSteps = ccs.getPossibleSteps()
	console.log("\"#{i}\": #{s.toString()}") for s, i in DSteps
	null
Sebastian Biewer's avatar
Sebastian Biewer committed
34
DP = (i) -> 		# remove?
Sebastian Biewer's avatar
Sebastian Biewer committed
35
36
37
	ccs.performStep(DSteps[i])
	DS()

38
39
40
41
42

class Environment
	constructor: -> @env = {}
	getValue: (id) ->
		res = @env[id]
Sebastian Biewer's avatar
Sebastian Biewer committed
43
		debugger
44
		throw ({message: "Unbound identifier '" + id + "'", line: @line, column: @column, name: "Evaluation Error"}) if ! res 	# ToDo: line not available
45
46
47
48
49
		res
	setValue: (id, type) ->
		@env[id] = type
	hasValue: (id) -> if @env[id] then true else false

Sebastian Biewer's avatar
Sebastian Biewer committed
50
CCSTypeUnknown = 3
Sebastian Biewer's avatar
Sebastian Biewer committed
51
52
CCSTypeChannel = 1
CCSTypeValue = 2
Sebastian Biewer's avatar
Sebastian Biewer committed
53
CCSTypeProcess = 10
Sebastian Biewer's avatar
Sebastian Biewer committed
54
55
56
57
CCSGetMostGeneralType = (t1, t2) ->
	return t1 if t2 == CCSTypeUnknown
	return t2 if t1 == CCSTypeUnknown
	return t1 if t1 == t2
58
	throw ({message: "Incompatible Types: #{CCSTypeToString t1} and #{CCSTypeToString t2}!", line: @line, column: @column, name: "Type Error"})		# ToDo: no line
Sebastian Biewer's avatar
Sebastian Biewer committed
59
60
61
62
63
64
65
66
67
68

CCSTypeToString = (t) ->
	if t == CCSTypeChannel
		"Channel"
	else if t == CCSTypeValue
		"Value"
	else if t == CCSTypeProcess
		"Process"
	else
		"Unknown"
Sebastian Biewer's avatar
Sebastian Biewer committed
69

70
class CCSEnvironment extends Environment
Sebastian Biewer's avatar
Sebastian Biewer committed
71
	constructor: (@ccs, @pd) -> super()
72
	getType: (id) -> @getValue id
Sebastian Biewer's avatar
Sebastian Biewer committed
73
74
75
	setType: (id, type) ->
		now = @env[id]
		if now
76
			throw ({message: "Duplicate process variable \"#{id}\"", line: @line, column: @column, name: "Type Error"}) if type == CCSTypeProcess		# ToDo: no line
Sebastian Biewer's avatar
Sebastian Biewer committed
77
78
79
			@env[id] = CCSGetMostGeneralType(now, type)
		else
			@env[id] = type
80
	hasType: (id) -> @hasValue id
81
	allowsUnrestrictedInputOnChannelName: (name) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
82
83
84
		if @pd and @pd.usesParameterName(name)
			false
		else
85
			@ccs.allowsUnrestrictedInputOnChannelName(name)
Sebastian Biewer's avatar
Sebastian Biewer committed
86
			
Sebastian Biewer's avatar
Sebastian Biewer committed
87

Sebastian Biewer's avatar
Sebastian Biewer committed
88

Sebastian Biewer's avatar
Sebastian Biewer committed
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

class CCSReplacementDescriptor
	constructor: -> @_items = {}

	updateForVariableWithExpression: (varName, expression) ->
		item = 
			"variableName": varName
			"expression": expression
			"replacement": "exp"
		@_items[varName] = item
		null

	updateForVariableWithChannelName: (varName, channelName) ->
		item = 
			"variableName": varName
			"channelName": channelName
			"replacement": "channel"
		@_items[varName] = item
		null

	hasReplacementInfoForVariableName: (varName) ->
		@_items[varName]?.replacement?

	variableHasExpressionReplacement: (varName) ->
		@_items[varName]?.replacement == "exp"

	variableHasChannelReplacement: (varName) ->
		@_items[varName]?.replacement == "channel"

	expressionForVariableName: (varName) ->
		@_items[varName]?.expression

	channelNameForVariableName: (varName) ->
		@_items[varName]?.channelName

	descriptorWithoutVariableName: (varName) ->
		res = new CCSReplacementDescriptor()
		for k,v of @_items
			res._items[k] = v if v.variableName != varName
		res



Sebastian Biewer's avatar
Sebastian Biewer committed
132
# - CCS
Sebastian Biewer's avatar
Sebastian Biewer committed
133
class CCS
134
	constructor: (@processDefinitions, @system, @allowUnguardedRecursion=true) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
135
		@warnings = []
Sebastian Biewer's avatar
Sebastian Biewer committed
136
		@unknownProcessDefnitions = {}
137
138
139
140
		if @system instanceof CCSRestriction
			@rootRestriction = @system
		else
			@rootRestriction = null
Sebastian Biewer's avatar
Sebastian Biewer committed
141
		@system.setCCS @
142
143
		penv = new CCSEnvironment(@)
		(pd.setCCS @) for pd in @processDefinitions
144
145
		@system.performAutoComplete(CCSStop)
		(pd.performAutoComplete(CCSStop, false)) for pd in @processDefinitions
146
		(pd.computeTypes(penv)) for pd in @processDefinitions
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
		# try
		@system.computeTypes(new CCSEnvironment(@))
		# catch e
		# 	e = new Error(e.message)
		# 	e.line = @system.line
		# 	e.column = 1
		# 	e.name = "TypeError"
		# 	e.code = @toString()
		# 	throw e

	setCodePos: (line, column) ->
		@line = line
		@column = column
		if @_exceptionBuffer
			e = @_exceptionBuffer
			@_exceptionBuffer = null
			e.line = line
			e.column = column
Sebastian Biewer's avatar
Sebastian Biewer committed
165
			throw e
166
		@
Sebastian Biewer's avatar
Sebastian Biewer committed
167
	
168
	allowsUnrestrictedInputOnChannelName: (name) ->
169
170
		if @rootRestriction then @rootRestriction.restrictsChannelName(name) else false
	
Sebastian Biewer's avatar
Sebastian Biewer committed
171
172
	getProcessDefinition: (name, argCount) -> 
		result = null
Sebastian Biewer's avatar
Sebastian Biewer committed
173
		(result = pd if pd.name == name and argCount == pd.getArgCount()) for pd in @processDefinitions
Sebastian Biewer's avatar
Sebastian Biewer committed
174
		if not result
Sebastian Biewer's avatar
Sebastian Biewer committed
175
			uid = "#{name}&#{argCount}"
Sebastian Biewer's avatar
Sebastian Biewer committed
176
177
178
179
			if @unknownProcessDefnitions[uid] != true
				@unknownProcessDefnitions[uid] = true
				warning = ({message: "Did not find definition for process \"#{name}\" with #{argCount} arguments. Assuming stop (0).", wholeFile:true, name: "Missing process definition"})
				@warnings.push(warning)
Sebastian Biewer's avatar
Sebastian Biewer committed
180
		return result
181
	getPossibleSteps: (copyOnPerform) -> @system.getPossibleSteps(copyOnPerform)
Sebastian Biewer's avatar
Sebastian Biewer committed
182
	#performStep: (step) -> @system = step.perform()
Sebastian Biewer's avatar
Sebastian Biewer committed
183
	
184
	toString: -> "#{ (process.toString() for process in @processDefinitions).join("") }\n#{ @system.toString() }";
Sebastian Biewer's avatar
Sebastian Biewer committed
185
186


Sebastian Biewer's avatar
Sebastian Biewer committed
187
# - ProcessDefinition
188
class CCSProcessDefinition
189
	constructor: (@name, @process, @params, @line=0) ->					# string x Process x CCSVariable*
Sebastian Biewer's avatar
Sebastian Biewer committed
190
		@column = 1
191
		@insertLinesBefore = 0 		# for toString... can be set by compiler for example
192
193
194
195
196
197
198
199
200
201
202

	setCodePos: (line, column) ->
		@line = line
		@column = column
		if @_exceptionBuffer
			e = @_exceptionBuffer
			@_exceptionBuffer = null
			e.line = line
			e.column = column
			throw e
		@
203
204
205
206
207
208
209
210
211
212
213

	performAutoComplete: (cls, force=true) ->
		if @__classesAutoCompleted
			return if not force
		else
			@__classesAutoCompleted = [] 
		if @__classesAutoCompleted.indexOf(cls) == -1
			@__classesAutoCompleted.push(cls)
			@process.performAutoComplete(cls)
		null
		
214
215
	
	getArgCount: -> if @params then @params.length else 0
Sebastian Biewer's avatar
Sebastian Biewer committed
216
217
218
219
	usesParameterName: (name) ->
		return false if not @params
		(return true if name == p.name) for p in @params
		false
220
221
	setCCS: (@ccs) -> 
		@process.setCCS @ccs
Sebastian Biewer's avatar
Sebastian Biewer committed
222
		@env = new CCSEnvironment(@ccs, @)
Sebastian Biewer's avatar
Sebastian Biewer committed
223
		if @params
Sebastian Biewer's avatar
Sebastian Biewer committed
224
			for x in @params
225
				@env.setType(x.name, CCSTypeUnknown)
226
	computeTypes: (penv) -> 
Sebastian Biewer's avatar
Sebastian Biewer committed
227
228
		if @process.isUnguardedRecursion()
			e = new Error("You are using unguarded recursion") 
Sebastian Biewer's avatar
Sebastian Biewer committed
229
			e.line = @line if not e.line
230
			e.column = 1
231
			e.name = if @ccs.allowUnguardedRecursion then "Type Warning" else "Type Error"
232
			e.code = @ccs.toString()
Sebastian Biewer's avatar
Sebastian Biewer committed
233
234
235
236
			if @ccs.allowUnguardedRecursion
				@ccs.warnings.push(e)
			else
				throw e	
Sebastian Biewer's avatar
Sebastian Biewer committed
237
238
239
240
241
242
243
244
		try
			penv.setType(@name, CCSTypeProcess)
			@process.computeTypes(@env)
		catch e
			e.line = @line if not e.line
			e.column = @column if not e.column
			throw e
		
Sebastian Biewer's avatar
Sebastian Biewer committed
245
246
	
	toString: -> 
247
248
249
		result = ""
		result += "\n" for i in [1..@insertLinesBefore] by 1
		result += @name
Sebastian Biewer's avatar
Sebastian Biewer committed
250
		result += "[#{@params.join ", "}]" if @params?.length > 0
Sebastian Biewer's avatar
Sebastian Biewer committed
251
252
253
254
		result +=" := #{@process.toString()}\n"
		return result;


Sebastian Biewer's avatar
Sebastian Biewer committed
255
# - Process (abstract class)
256
class CCSProcess
Sebastian Biewer's avatar
Sebastian Biewer committed
257
	constructor: (@subprocesses...) ->								# Process*
Sebastian Biewer's avatar
Sebastian Biewer committed
258
		@__id = ObjID++
259
260
261
262
263
264
265
266
267
268
269

	setCodePos: (line, column) ->
		@line = line
		@column = column
		if @_exceptionBuffer
			e = @_exceptionBuffer
			@_exceptionBuffer = null
			e.line = line
			e.column = column
			throw e
		@
Sebastian Biewer's avatar
Sebastian Biewer committed
270
		
Sebastian Biewer's avatar
Sebastian Biewer committed
271
	setCCS: (@ccs) -> p.setCCS(@ccs) for p in @subprocesses
Sebastian Biewer's avatar
Sebastian Biewer committed
272
	_setCCS: (@ccs) -> throw "no ccs" if !@ccs; @
Sebastian Biewer's avatar
Sebastian Biewer committed
273
274
275
276
	getLeft: -> @subprocesses[0]
	getRight: -> @subprocesses[1]
	setLeft: (left) -> @subprocesses[0] = left
	setRight: (right) -> @subprocesses[1] = right
277
278
279
280

	performAutoComplete: (cls) ->		# auto complete stop or exit
		p.performAutoComplete(cls) for p in @subprocesses
		null
Sebastian Biewer's avatar
Sebastian Biewer committed
281
	
Sebastian Biewer's avatar
Sebastian Biewer committed
282
283
284
285
	# replaceVariable: (varName, exp) -> 
	# 	p.replaceVariable(varName, exp) for p in @subprocesses
	applyReplacementDescriptor: (replaces) ->
		p.applyReplacementDescriptor(replaces) for p in @subprocesses
Sebastian Biewer's avatar
Sebastian Biewer committed
286
	replaceVariableWithValue: (varName, val) -> 
Sebastian Biewer's avatar
Sebastian Biewer committed
287
288
289
290
291
		replacer = new CCSReplacementDescriptor()
		replacer.updateForVariableWithExpression(varName, new CCSConstantExpression(val))
		@applyReplacementDescriptor(replacer)
	# replaceChannelName: (old, newID) ->
	# 	p.replaceChannelName(old, newID) for p in @subprocesses
Sebastian Biewer's avatar
Sebastian Biewer committed
292
	computeTypes: (env) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
293
294
295
296
297
298
		try
			p.computeTypes(env) for p in @subprocesses
		catch e
			e.line = @line if not e.line
			e.column = @column if not e.column
			throw e
Sebastian Biewer's avatar
Sebastian Biewer committed
299
		null
300
301
302
	isUnguardedRecursion: ->
		(return true if p.isUnguardedRecursion()) for p in @subprocesses
		false
Sebastian Biewer's avatar
Sebastian Biewer committed
303
	
Sebastian Biewer's avatar
Sebastian Biewer committed
304
	getApplicapleRules: -> []
Sebastian Biewer's avatar
Sebastian Biewer committed
305
	_getPossibleSteps: (info, copyOnPerform) -> 
306
		copyOnPerform = false if not copyOnPerform
Sebastian Biewer's avatar
Sebastian Biewer committed
307
		res = SBArrayConcatChildren(rule.getPossibleSteps(this, info, copyOnPerform) for rule in @getApplicapleRules())
Sebastian Biewer's avatar
Sebastian Biewer committed
308
	getPossibleSteps: (copyOnPerform) -> CCSExpandInput(@_getPossibleSteps({}, copyOnPerform))
Sebastian Biewer's avatar
Sebastian Biewer committed
309
		
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
	isLeftAssociative: -> false
	isRightAssociative: -> false

	needsBracketsForSubprocess: (process, left) -> 
		if @getPrecedence? and process.getPrecedence?
			precedence = process.getPrecedence()
		else
			return false
		# Adjust precedence according to associativity
		if @isLeftAssociative() and left == false
			precedence -= 0.5
		else if @isRightAssociative() and left == true
			precedence -= 0.5

		precedence < @getPrecedence()

	stringForSubprocess: (process, mini, left) ->
		if @needsBracketsForSubprocess(process, left)
Sebastian Biewer's avatar
Sebastian Biewer committed
328
			"(#{process.toString(mini)})"
Sebastian Biewer's avatar
Sebastian Biewer committed
329
		else
Sebastian Biewer's avatar
Sebastian Biewer committed
330
			"#{process.toString(mini)}"
331
332
	getPrefixes: -> SBArrayConcatChildren(p.getPrefixes() for p in @subprocesses)
	getExits: -> SBArrayConcatChildren(p.getExits() for p in @subprocesses)
Sebastian Biewer's avatar
Sebastian Biewer committed
333

Sebastian Biewer's avatar
Sebastian Biewer committed
334
335
	

Sebastian Biewer's avatar
Sebastian Biewer committed
336
# - Stop
Sebastian Biewer's avatar
Sebastian Biewer committed
337
class CCSStop extends CCSProcess
Sebastian Biewer's avatar
Sebastian Biewer committed
338
339
	getPrecedence: -> 12
	toString: -> "0"
Sebastian Biewer's avatar
Sebastian Biewer committed
340
	copy: -> (new CCSStop())._setCCS(@ccs)
Sebastian Biewer's avatar
Sebastian Biewer committed
341
	
Sebastian Biewer's avatar
Sebastian Biewer committed
342
343

# - Exit
Sebastian Biewer's avatar
Sebastian Biewer committed
344
class CCSExit extends CCSProcess
Sebastian Biewer's avatar
Sebastian Biewer committed
345
	getPrecedence: -> 12
Sebastian Biewer's avatar
Sebastian Biewer committed
346
	getApplicapleRules: -> [CCSExitRule]
Sebastian Biewer's avatar
Sebastian Biewer committed
347
	getExits: -> [@]
Sebastian Biewer's avatar
Sebastian Biewer committed
348
	toString: -> "1"
Sebastian Biewer's avatar
Sebastian Biewer committed
349
	copy: -> (new CCSExit())._setCCS(@ccs)
350
351
352

# class CCSAutoComplete extends CCSProcess
# 	getPrecedence: -> 12
Sebastian Biewer's avatar
Sebastian Biewer committed
353
354
355
	
	
	
Sebastian Biewer's avatar
Sebastian Biewer committed
356
# - ProcessApplication
Sebastian Biewer's avatar
Sebastian Biewer committed
357
class CCSProcessApplication extends CCSProcess
Sebastian Biewer's avatar
Sebastian Biewer committed
358
	constructor: (@processName, @valuesToPass=[]) -> super()		# string x Expression list
359
360

	performAutoComplete: (cls) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
361
		@getProcessDefinition()?.performAutoComplete(cls)
Sebastian Biewer's avatar
Sebastian Biewer committed
362
	
Sebastian Biewer's avatar
Sebastian Biewer committed
363
	getArgCount: -> @valuesToPass.length
Sebastian Biewer's avatar
Sebastian Biewer committed
364
	getProcessDefinition: -> @ccs.getProcessDefinition(@processName, @getArgCount())
Sebastian Biewer's avatar
Sebastian Biewer committed
365
366
	getProcess: -> 
		return @process if @process
Sebastian Biewer's avatar
Sebastian Biewer committed
367
		pd = @getProcessDefinition()
Sebastian Biewer's avatar
Sebastian Biewer committed
368
369
370
		if not pd
			@process = new CCSStop()._setCCS(@ccs).setCodePos(@line, @column)
			return @process
Sebastian Biewer's avatar
Sebastian Biewer committed
371
		@process = pd.process.copy()
Sebastian Biewer's avatar
Sebastian Biewer committed
372
		if pd.params
Sebastian Biewer's avatar
Sebastian Biewer committed
373
			replaces = new CCSReplacementDescriptor()
374
			for i in [0..pd.params.length-1] by 1
375
				id = pd.params[i].name
Sebastian Biewer's avatar
Sebastian Biewer committed
376
377
				# Note: if a variable exp cannot be typed, it is probably a channel name. Example: P[a,b] := c!.P[a,b]
				# Note 2: Maybe, but probably is not enough here. Imagine P[2,3]: a is a constant expression, which does not have a .variableName!
Sebastian Biewer's avatar
Sebastian Biewer committed
378
379
380
381
382
383
				try
					type = pd.env.getType(id)
				catch e
					e.line = @line if not e.line
					e.column = @column if not e.column
					throw e
Sebastian Biewer's avatar
Sebastian Biewer committed
384
385
386
				if type == CCSTypeUnknown
					type = if @valuesToPass[i].variableName then CCSTypeChannel else CCSTypeValue
				if type == CCSTypeChannel  
Sebastian Biewer's avatar
Sebastian Biewer committed
387
388
					replaces.updateForVariableWithChannelName(id, @valuesToPass[i].variableName)
					# @process.replaceChannelName(id, @valuesToPass[i].variableName)
Sebastian Biewer's avatar
Sebastian Biewer committed
389
				else
390
391
392
					if !(pd.params[i].allowsValue(@valuesToPass[i].evaluate()))
						@process = null
						return null
Sebastian Biewer's avatar
Sebastian Biewer committed
393
394
395
					replaces.updateForVariableWithExpression(id, @valuesToPass[i])
					# @process.replaceVariable(id, @valuesToPass[i])	
			@process.applyReplacementDescriptor(replaces)
Sebastian Biewer's avatar
Sebastian Biewer committed
396
397
		@process
	getPrecedence: -> 12
Sebastian Biewer's avatar
Sebastian Biewer committed
398

Sebastian Biewer's avatar
Sebastian Biewer committed
399
	computeTypes: (env) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
400
401
402
		pd = @getProcessDefinition()
		return if not pd
		# throw ({message: "Unknown process variable \"#{@processName}\" (with #{@getArgCount()} arguments)!", line: @line, column: @column, name: "Type Error"}) if not pd
Sebastian Biewer's avatar
Sebastian Biewer committed
403
404
405
406
407
408
409
410
411
		try
			if pd.params
				for i in [0..pd.params.length-1] by 1
					type = @valuesToPass[i].computeTypes(env, true)
					pd.env.setType(pd.params[i].name, type)
		catch e
			e.line = @line if not e.line
			e.column = @column if not e.column
			throw e
Sebastian Biewer's avatar
Sebastian Biewer committed
412
		super
Sebastian Biewer's avatar
Sebastian Biewer committed
413
	isUnguardedRecursion: -> @getProcessDefinition() != null
414
	
Sebastian Biewer's avatar
Sebastian Biewer committed
415
	getApplicapleRules: -> [CCSRecRule]
Sebastian Biewer's avatar
Sebastian Biewer committed
416
417
	getPrefixes : -> @getProcess().getPrefixes() #if @process then @process.getPrefixes() else []
	getExits: -> if @process then @process.getExits() else []
Sebastian Biewer's avatar
Sebastian Biewer committed
418
419
420
421
422
423
	applyReplacementDescriptor: (replaces) ->
		@valuesToPass = (e.applyReplacementDescriptor(replaces) for e in @valuesToPass)
	# replaceVariable: (varName, exp) -> 
	# 	@valuesToPass = (e.replaceVariable(varName, exp) for e in @valuesToPass)
	# replaceChannelName: (old, newID) -> 
	# 	e.replaceChannelName(old, newID) for e in @valuesToPass
Sebastian Biewer's avatar
Sebastian Biewer committed
424
425
426
	###getProxy: -> 	# ToDo: cache result
		pd = @ccs.getProcessDefinition(@processName, @getArgCount())
		new ProcessApplicationProxy(@, pd.process.copy())###
Sebastian Biewer's avatar
Sebastian Biewer committed
427
	
Sebastian Biewer's avatar
Sebastian Biewer committed
428
	toString: (mini) -> 
Sebastian Biewer's avatar
Sebastian Biewer committed
429
		result = @processName
Sebastian Biewer's avatar
Sebastian Biewer committed
430
		result += "[#{(e.toString(mini) for e in @valuesToPass).join ", "}]" if @getArgCount()>0
Sebastian Biewer's avatar
Sebastian Biewer committed
431
		return result
Sebastian Biewer's avatar
Sebastian Biewer committed
432
		
Sebastian Biewer's avatar
Sebastian Biewer committed
433
	copy: -> (new CCSProcessApplication(@processName, v.copy() for v in @valuesToPass))._setCCS(@ccs)
Sebastian Biewer's avatar
Sebastian Biewer committed
434
435
436
437



# - Prefix
Sebastian Biewer's avatar
Sebastian Biewer committed
438
class CCSPrefix extends CCSProcess
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
	constructor: (@action, process) -> 
		if process 
			super process	
		else 
			super []...	# Action x Process

	performAutoComplete: (cls) ->
		if @subprocesses.length == 0
			@subprocesses[0] = new cls()
			@subprocesses[0].setCCS(@ccs)
			@__autoCompleted = cls
		else
			if @__autoCompleted and @__autoCompleted != cls
				warning = ({message: "Auto-completion of CCS process is ambiguous. Inferred as exit (1).", line: @line, column: @column, name: "Auto-completion"})
				@subprocesses[0] = new CCSExit()
				@subprocesses[0].setCCS(@ccs)
				@__autoCompleted = CCSExit
				@ccs.warnings.push(warning)
			super
Sebastian Biewer's avatar
Sebastian Biewer committed
458
459
	
	getPrecedence: -> 12
Sebastian Biewer's avatar
Sebastian Biewer committed
460
	getApplicapleRules: -> [CCSPrefixRule, CCSOutputRule, CCSInputRule, CCSMatchRule]
Sebastian Biewer's avatar
Sebastian Biewer committed
461
	getProcess: -> @subprocesses[0]
Sebastian Biewer's avatar
Sebastian Biewer committed
462
	
Sebastian Biewer's avatar
Sebastian Biewer committed
463
464
465
466
467
468
469
470
	applyReplacementDescriptor: (replaces) ->
		replaces = @action.applyReplacementDescriptor(replaces)
		super(replaces)
	# replaceVariable: (varName, exp) ->
	# 	super varName, exp if @action.replaceVariable(varName, exp)
	# replaceChannelName: (old, newID) ->
	# 	@action.replaceChannelName(old, newID)
	# 	super old, newID #if @action.replaceChannelName(old, newID)
Sebastian Biewer's avatar
Sebastian Biewer committed
471
	getPrefixes: -> return [@]
Sebastian Biewer's avatar
Sebastian Biewer committed
472
	computeTypes: (env) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
473
474
475
476
477
478
		try
			@action.computeTypes(env)
		catch e
			e.line = @line if not e.line
			e.column = @column if not e.column
			throw e
Sebastian Biewer's avatar
Sebastian Biewer committed
479
		super
480
	isUnguardedRecursion: -> false
Sebastian Biewer's avatar
Sebastian Biewer committed
481
			
Sebastian Biewer's avatar
Sebastian Biewer committed
482
		
Sebastian Biewer's avatar
Sebastian Biewer committed
483
	toString: (mini) -> "#{@action.toString(mini)}.#{@stringForSubprocess(@getProcess(), mini)}"
Sebastian Biewer's avatar
Sebastian Biewer committed
484
	copy: -> (new CCSPrefix(@action.copy(), @getProcess().copy()))._setCCS(@ccs)
Sebastian Biewer's avatar
Sebastian Biewer committed
485
486


Sebastian Biewer's avatar
Sebastian Biewer committed
487
# - Condition
Sebastian Biewer's avatar
Sebastian Biewer committed
488
class CCSCondition extends CCSProcess
489
	constructor: (@expression, process) -> super process		# Expression x Process
Sebastian Biewer's avatar
Sebastian Biewer committed
490
491
	
	getPrecedence: -> 12
Sebastian Biewer's avatar
Sebastian Biewer committed
492
	getApplicapleRules: -> [CCSCondRule]
493
	getProcess: -> @subprocesses[0]
Sebastian Biewer's avatar
Sebastian Biewer committed
494

Sebastian Biewer's avatar
Sebastian Biewer committed
495
	computeTypes: (env) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
496
497
498
499
500
501
		try
			type = @expression.computeTypes(env, false)
		catch e
			e.line = @line if not e.line
			e.column = @column if not e.column
			throw e
502
		throw ({message: "Conditions can only check values. Channel names are not supported!", line: @line, column: @column, name: "Evaluation Error"}) if type == CCSTypeChannel
Sebastian Biewer's avatar
Sebastian Biewer committed
503
		super
Sebastian Biewer's avatar
Sebastian Biewer committed
504
505
506
507
508
509
	applyReplacementDescriptor: (replaces) ->
		@expression = @expression.applyReplacementDescriptor(replaces)
		super
	# replaceVariable: (varName, exp) ->
	# 	@expression = @expression.replaceVariable(varName, exp)
	# 	super varName, exp
Sebastian Biewer's avatar
Sebastian Biewer committed
510
	
Sebastian Biewer's avatar
Sebastian Biewer committed
511
	toString: (mini) -> "when (#{@expression.toString(mini)}) #{@stringForSubprocess(@getProcess(), mini)}"
Sebastian Biewer's avatar
Sebastian Biewer committed
512
	copy: -> (new CCSCondition(@expression.copy(), @getProcess().copy()))._setCCS(@ccs)
Sebastian Biewer's avatar
Sebastian Biewer committed
513

Sebastian Biewer's avatar
Sebastian Biewer committed
514

Sebastian Biewer's avatar
Sebastian Biewer committed
515
# - Choice
Sebastian Biewer's avatar
Sebastian Biewer committed
516
class CCSChoice extends CCSProcess
Sebastian Biewer's avatar
Sebastian Biewer committed
517
	constructor: (left, right) -> super left, right		# Process x Process
Sebastian Biewer's avatar
Sebastian Biewer committed
518
519
	
	getPrecedence: -> 9
520
	isLeftAssociative: -> true
Sebastian Biewer's avatar
Sebastian Biewer committed
521
	getApplicapleRules: -> [CCSChoiceLRule, CCSChoiceRRule]
Sebastian Biewer's avatar
Sebastian Biewer committed
522
	
523
	toString: (mini) -> "#{@stringForSubprocess(@getLeft(), mini, true)} + #{@stringForSubprocess(@getRight(), mini, false)}"
Sebastian Biewer's avatar
Sebastian Biewer committed
524
	copy: -> (new CCSChoice(@getLeft().copy(), @getRight().copy()))._setCCS(@ccs)
Sebastian Biewer's avatar
Sebastian Biewer committed
525
526
527


# - Parallel
Sebastian Biewer's avatar
Sebastian Biewer committed
528
class CCSParallel extends CCSProcess
Sebastian Biewer's avatar
Sebastian Biewer committed
529
	constructor: (left, right) -> super left, right		# Process x Process
Sebastian Biewer's avatar
Sebastian Biewer committed
530
531
	
	getPrecedence: -> 6
532
	isLeftAssociative: -> true
Sebastian Biewer's avatar
Sebastian Biewer committed
533
	getApplicapleRules: -> [CCSParLRule, CCSParRRule, CCSSyncRule, CCSSyncExitRule]
Sebastian Biewer's avatar
Sebastian Biewer committed
534
	
535
	toString: (mini) -> "#{@stringForSubprocess(@getLeft(), mini, true)} | #{@stringForSubprocess(@getRight(), mini, false)}"
Sebastian Biewer's avatar
Sebastian Biewer committed
536
	copy: -> (new CCSParallel(@getLeft().copy(), @getRight().copy()))._setCCS(@ccs)
Sebastian Biewer's avatar
Sebastian Biewer committed
537

Sebastian Biewer's avatar
Sebastian Biewer committed
538

Sebastian Biewer's avatar
Sebastian Biewer committed
539
# - Sequence
Sebastian Biewer's avatar
Sebastian Biewer committed
540
class CCSSequence extends CCSProcess
Sebastian Biewer's avatar
Sebastian Biewer committed
541
	constructor: (left, right) -> super left, right		# Process x Process
542
543
544
545

	performAutoComplete: (cls) ->
		@getLeft().performAutoComplete(CCSExit)
		@getRight().performAutoComplete(cls)
Sebastian Biewer's avatar
Sebastian Biewer committed
546
547
	
	getPrecedence: -> 3
548
	isLeftAssociative: -> true
Sebastian Biewer's avatar
Sebastian Biewer committed
549
	getApplicapleRules: -> [CCSSeq1Rule, CCSSeq2Rule]
Sebastian Biewer's avatar
Sebastian Biewer committed
550
551
	getPrefixes: -> @getLeft().getPrefixes()
	getExits: -> @getLeft().getExits()
552
553

	isUnguardedRecursion: -> @getLeft().isUnguardedRecursion() 		# if the left process is guarded, then the complete expression is, because the right one is guarded by a tau
Sebastian Biewer's avatar
Sebastian Biewer committed
554
	
555
	toString: (mini) -> "#{@stringForSubprocess(@getLeft(), mini, true)} ; #{@stringForSubprocess(@getRight(), mini, false)}"
Sebastian Biewer's avatar
Sebastian Biewer committed
556
	copy: -> (new CCSSequence(@getLeft().copy(), @getRight().copy()))._setCCS(@ccs)
Sebastian Biewer's avatar
Sebastian Biewer committed
557
558


Sebastian Biewer's avatar
Sebastian Biewer committed
559
# - Restriction		
Sebastian Biewer's avatar
Sebastian Biewer committed
560
# !! Changed precedence to binding stronger than choice and weaker than prefix
Sebastian Biewer's avatar
Sebastian Biewer committed
561
562
class CCSRestriction extends CCSProcess
	constructor: (process, @restrictedChannels) -> super process	# Process x string*
Sebastian Biewer's avatar
Sebastian Biewer committed
563
	
Sebastian Biewer's avatar
Sebastian Biewer committed
564
	getPrecedence: -> 10
Sebastian Biewer's avatar
Sebastian Biewer committed
565
	getApplicapleRules: -> [CCSResRule]
Sebastian Biewer's avatar
Sebastian Biewer committed
566
567
	getProcess: -> @subprocesses[0]
	setProcess: (process) -> @subprocesses[0] = process 
568
569
570
571
	restrictsChannelName: (name) ->
		return false if name == CCSInternalChannel or name == CCSExitChannel
		return false if @restrictedChannels.length == 0
		if @restrictedChannels[0] == "*" then @restrictedChannels.indexOf(name) == -1 else @restrictedChannels.indexOf(name) != -1
Sebastian Biewer's avatar
Sebastian Biewer committed
572
	
Sebastian Biewer's avatar
Sebastian Biewer committed
573
	toString: (mini) -> "#{@stringForSubprocess(@getProcess(), mini)} \\ {#{@restrictedChannels.join ", "}}"
Sebastian Biewer's avatar
Sebastian Biewer committed
574
	copy: -> (new CCSRestriction(@getProcess().copy(), @restrictedChannels))._setCCS(@ccs)
Sebastian Biewer's avatar
Sebastian Biewer committed
575
576
	

Sebastian Biewer's avatar
Sebastian Biewer committed
577

Sebastian Biewer's avatar
Sebastian Biewer committed
578
579
	

Sebastian Biewer's avatar
Sebastian Biewer committed
580
# --------------------
Sebastian Biewer's avatar
Sebastian Biewer committed
581
582
# - Channel

583
class CCSChannel
Sebastian Biewer's avatar
Sebastian Biewer committed
584
	constructor: (@name, @expression=null) ->	# string x Expression
585
586
587
588
589
590
591
592
593
594
595

	setCodePos: (line, column) ->
		@line = line
		@column = column
		if @_exceptionBuffer
			e = @_exceptionBuffer
			@_exceptionBuffer = null
			e.line = line
			e.column = column
			throw e
		@
Sebastian Biewer's avatar
Sebastian Biewer committed
596
597
598
	
	isEqual: (channel) ->
		return false if channel.name != @name
Sebastian Biewer's avatar
Sebastian Biewer committed
599
600
		return true if not channel.expression and not @expression
		return false if not channel.expression or not @expression
Sebastian Biewer's avatar
Sebastian Biewer committed
601
		return channel.expression.evaluate() == @expression.evaluate()
Sebastian Biewer's avatar
Sebastian Biewer committed
602
603
604
605
	applyReplacementDescriptor: (replaces) ->
		@expression = @expression.applyReplacementDescriptor(replaces) if @expression
		if replaces.variableHasChannelReplacement(@name)
			@name = replaces.channelNameForVariableName(@name)
Sebastian Biewer's avatar
Sebastian Biewer committed
606
		null
Sebastian Biewer's avatar
Sebastian Biewer committed
607

Sebastian Biewer's avatar
Sebastian Biewer committed
608
	computeTypes: (env) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
609
610
611
612
613
614
615
616
617
		try
			env.setType(@name, CCSTypeChannel)
			if @expression
				type = @expression.computeTypes(env, false)
				throw ({message: "Channel variables are not allowed in channel specifier expression!", line: @line, column: @column, name: "Type Error"}) if type == CCSTypeChannel
		catch e
			e.line = @line if not e.line
			e.column = @column if not e.column
			throw e
Sebastian Biewer's avatar
Sebastian Biewer committed
618
		null
Sebastian Biewer's avatar
Sebastian Biewer committed
619
	toString: (mini) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
620
621
		result = "" + @name
		if @expression
Sebastian Biewer's avatar
Sebastian Biewer committed
622
623
624
625
				#if @expression.isEvaluatable()
				#	result += "(#{@expression.evaluate()})"
				#else
				result += "(#{@expression.toString(mini)})"
Sebastian Biewer's avatar
Sebastian Biewer committed
626
		result
Sebastian Biewer's avatar
Sebastian Biewer committed
627
	copy: -> new CCSChannel(@name, @expression?.copy())
Sebastian Biewer's avatar
Sebastian Biewer committed
628
629
630
	
	

Sebastian Biewer's avatar
Sebastian Biewer committed
631
# -- Action (abstract class)
632
633
class CCSAction
	constructor: (@channel) ->		# CCSChannel
Sebastian Biewer's avatar
Sebastian Biewer committed
634
		if @channel.name == "i"		# ??? TODO @channel is not a string?
635
636
637
			if !@isSimpleAction() 
				@_exceptionBuffer = ({message: "Internal channel i is only allowed as simple action!", line: @line, column: @column, name: "Parse Error"})
				return
Sebastian Biewer's avatar
Sebastian Biewer committed
638
639
			@channel.name = CCSInternalChannel
		else if @channel.name == "e"
640
641
642
			if !@isSimpleAction() 
				@_exceptionBuffer = ({message: "Exit channel e is only allowed as simple action!", line: @line, column: @column, name: "Parse Error"})
				return
Sebastian Biewer's avatar
Sebastian Biewer committed
643
			@channel.name = CCSExitChannel
644
645
646
647
648
649
650
651
652
653
654

	setCodePos: (line, column) ->
		@line = line
		@column = column
		if @_exceptionBuffer
			e = @_exceptionBuffer
			@_exceptionBuffer = null
			e.line = line
			e.column = column
			throw e
		@
Sebastian Biewer's avatar
Sebastian Biewer committed
655
656
657
658
659
660
	
	isSimpleAction: -> false
	isInputAction: -> false
	isMatchAction: -> false
	isOutputAction: ->false
	
Sebastian Biewer's avatar
Sebastian Biewer committed
661
662
	isInternalAction: -> @channel.name == CCSInternalChannel or @channel.name == CCSExitChannel
	
Sebastian Biewer's avatar
Sebastian Biewer committed
663
	
Sebastian Biewer's avatar
Sebastian Biewer committed
664
665
	toString: (mini) -> @channel.toString(mini)
	transferDescription: -> @channel.toString(true)
Sebastian Biewer's avatar
Sebastian Biewer committed
666
	isSyncableWithAction: (action) -> false
Sebastian Biewer's avatar
Sebastian Biewer committed
667
668
669
	applyReplacementDescriptor: (replaces) ->
		@channel.applyReplacementDescriptor(replaces)
		replaces
Sebastian Biewer's avatar
Sebastian Biewer committed
670
671
672
673
674
675
676
677
678
	

	computeTypes: (env) -> 
		try
			@channel.computeTypes(env)
		catch e
			e.line = @line if not e.line
			e.column = @column if not e.column
			throw e
Sebastian Biewer's avatar
Sebastian Biewer committed
679
680


Sebastian Biewer's avatar
Sebastian Biewer committed
681
# - Simple Action
Sebastian Biewer's avatar
Sebastian Biewer committed
682
class CCSSimpleAction extends CCSAction
Sebastian Biewer's avatar
Sebastian Biewer committed
683
	isSimpleAction: -> true
Sebastian Biewer's avatar
Sebastian Biewer committed
684
685
	supportsValuePassing: -> false
	copy: -> new CCSSimpleAction(@channel.copy())
Sebastian Biewer's avatar
Sebastian Biewer committed
686
687
688
689
690

CCSInternalActionCreate = (name) -> 
	if name != CCSInternalChannel and name != CCSExitChannel
		throw new Error("Only internal channel names are allowed!")
	new CCSSimpleAction(new CCSChannel(name, null))
Sebastian Biewer's avatar
Sebastian Biewer committed
691
692


693
694
695

class CCSVariable
	constructor: (@name, @set) -> throw new Error("Illegal variable name") if typeof @name != "string" or @name.length == 0
696
697
698
699
700
701
702
703
704
705
706
707

	setCodePos: (line, column) ->
		@line = line
		@column = column
		if @_exceptionBuffer
			e = @_exceptionBuffer
			@_exceptionBuffer = null
			e.line = line
			e.column = column
			throw e
		@

708
709
	allowsValue: (value) -> if @set then @set.allowsValue value else true
	possibleValues: ->
710
711
		throw ({message: "Unrestricted variable! Restrict using the 'range' syntax.", line: @line, column: @column, name: "Evaluation Error"}) if not @set
		# throw new Error("Cannot generate infinite values for unrestricted variables!") if not @set
712
713
714
715
		@set.possibleValues()
	toString: -> "#{@name}#{if @set then ":"+@set.toString() else ""}"


716
717
718
class CCSValueSet
	constructor: (@type, @min, @max) ->
		throw new Error("Unknown Type") if @type != "string" and @type != "number"
719
720
721
722
723
724
725
726
727
728
729
730

	setCodePos: (line, column) ->
		@line = line
		@column = column
		if @_exceptionBuffer
			e = @_exceptionBuffer
			@_exceptionBuffer = null
			e.line = line
			e.column = column
			throw e
		@

731
732
733
734
735
736
737
738
739
740
741
	allowsValue: (value) ->
		value = CCSStringDataForValue(value)
		if @type == "string"
			len = ("" + value).length
			len >= @min and len <= @max
		else
			if CCSValueIsInt(value)
				val = parseInt(value)
				val >= @min and val <= @max
			else
				false
742
743
	possibleValues: ->
		if @type == "string"
744
745
746
747
748
749
750
751
752
753
754
755
756
757
			res = [""]
			t = []
			for i in [0...@min] by 1
				for s in res
					for c in CCSValueSet.allowedChars
						t.push(s+c)
				res = t
				t = []
			for i in [@min...@max] by 1
				for s in res
					for c in CCSValueSet.allowedChars
						t.push(s+c)
				res = res.concat(t)
			res
758
		else
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
			[@min..@max]
	toString: ->
		if @type == "string"
			res = ""
			for i in [0...@min] by 1
				res += "$"
			res += ".."
			for i in [0...@max] by 1
				res += "$"
			res
		else
			"#{@min}..#{@max}"


CCSValueSet.allowedChars = (->
	res = []
	for i in [65..90] by 1
		res.push(String.fromCharCode(i))
	for i in [97..122] by 1
		res.push(String.fromCharCode(i))
	res.push("-")
	res
)()
782
783
	

Sebastian Biewer's avatar
Sebastian Biewer committed
784
# - Input
Sebastian Biewer's avatar
Sebastian Biewer committed
785
class CCSInput extends CCSAction
786
	constructor: (channel, @variable) -> 		# CCSChannel x CCSVariable
Sebastian Biewer's avatar
Sebastian Biewer committed
787
		super channel
Sebastian Biewer's avatar
Sebastian Biewer committed
788
789
	
	isInputAction: -> true
790
791
	supportsValuePassing: -> if @variable then true else false
	isSyncableWithAction: (action) -> action?.isOutputAction() and action.channel.isEqual(@channel) and (if action.supportsValuePassing() then @supportsValuePassing() and @variable.allowsValue(action.expression.evaluate()) else not @supportsValuePassing())
Sebastian Biewer's avatar
Sebastian Biewer committed
792
793
794
795
796
797
	applyReplacementDescriptor: (replaces) ->
		super
		if @variable then replaces.descriptorWithoutVariableName(@variable.name) else replaces 		# return new replaces without current varName to stop further replacing
	# replaceVariable: (varName, exp) -> 
	# 	super varName, exp
	# 	not @variable or @variable.name != varName	# stop replacing if identifier is equal to its own variable name
798
	allowsValueAsInput: (value) -> @variable.allowsValue(value)
799
	
Sebastian Biewer's avatar
Sebastian Biewer committed
800
	computeTypes: (env) ->
801
		if @supportsValuePassing()
802
			env.setType(@variable.name, CCSTypeValue) 
803
804
			if not env.allowsUnrestrictedInputOnChannelName(@channel.name)
				throw ({message: "Unrestricted input variable \"#{@variable}\". Use the 'range' syntax to add a restriction.", line: @line, column: @column, name: "Type Error"}) if not @variable.set
Sebastian Biewer's avatar
Sebastian Biewer committed
805
		super
Sebastian Biewer's avatar
Sebastian Biewer committed
806
	
807
808
809
	toString: (mini, inputValue) -> 
		inputValue = null if inputValue == undefined
		"#{super}?#{ if @supportsValuePassing() then (if inputValue != null then CCSBestStringForValue inputValue else @variable.toString()) else ""}"
810
811
812
813
	transferDescription: (inputValue) -> 
		if @supportsValuePassing() and (inputValue == null or inputValue == undefined)
			throw new Error("CCSInput.transferDescription needs an input value as argument if it supports value passing!") 
		"#{super}#{ if @supportsValuePassing() then ": " + inputValue else ""}"
Sebastian Biewer's avatar
Sebastian Biewer committed
814
	copy: -> new CCSInput(@channel.copy(), @variable, @range)
Sebastian Biewer's avatar
Sebastian Biewer committed
815
816


Sebastian Biewer's avatar
Sebastian Biewer committed
817

Sebastian Biewer's avatar
Sebastian Biewer committed
818
# - Match
Sebastian Biewer's avatar
Sebastian Biewer committed
819
class CCSMatch extends CCSAction
820
	constructor: (channel, @expression) -> super channel	# CCSChannel x Expression
Sebastian Biewer's avatar
Sebastian Biewer committed
821
822
823
	
	isMatchAction: -> true
	supportsValuePassing: -> true
Sebastian Biewer's avatar
Sebastian Biewer committed
824
	isSyncableWithAction: (action) -> action?.isOutputAction() and action.channel.isEqual(@channel) and action.supportsValuePassing() and action.expression.evaluate() == this.expression.evaluate()
Sebastian Biewer's avatar
Sebastian Biewer committed
825
826
827
828
	applyReplacementDescriptor: (replaces) ->
		super
		@expression = @expression.applyReplacementDescriptor(replaces)
		replaces
Sebastian Biewer's avatar
Sebastian Biewer committed
829

Sebastian Biewer's avatar
Sebastian Biewer committed
830
	computeTypes: (env) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
831
832
833
834
835
836
		try
			type = @expression.computeTypes(env, false)
		catch e
			e.line = @line if not e.line
			e.column = @column if not e.column
			throw e
Sebastian Biewer's avatar
Sebastian Biewer committed
837
838
		throw new Error("Channels can not be sent over channels!") if type == CCSTypeChannel
		super
Sebastian Biewer's avatar
Sebastian Biewer committed
839
	
Sebastian Biewer's avatar
Sebastian Biewer committed
840
841
842
843
	toString: (mini) -> "#{super}?(#{if @expression then @expression.toString(mini) else ""})"
	transferDescription: -> "#{super}:#{@expression.evaluate()}"
	copy: -> new CCSMatch(@channel.copy(), @expression.copy())

Sebastian Biewer's avatar
Sebastian Biewer committed
844
	
Sebastian Biewer's avatar
Sebastian Biewer committed
845
846

# - Output
Sebastian Biewer's avatar
Sebastian Biewer committed
847
class CCSOutput extends CCSAction
848
	constructor: (channel, @expression) -> super channel	# CCSChannel x Expression
Sebastian Biewer's avatar
Sebastian Biewer committed
849
	
Sebastian Biewer's avatar
Sebastian Biewer committed
850
	isOutputAction: -> true
Sebastian Biewer's avatar
Sebastian Biewer committed
851
	supportsValuePassing: -> @expression instanceof CCSExpression
Sebastian Biewer's avatar
Sebastian Biewer committed
852
853
854
855
856
	isSyncableWithAction: (action) -> 
		if action?.isInputAction() or action.isMatchAction()
			action.isSyncableWithAction(this)
		else
			false
Sebastian Biewer's avatar
Sebastian Biewer committed
857
858
859
860
	applyReplacementDescriptor: (replaces) ->
		super
		@expression = @expression.applyReplacementDescriptor(replaces) if @expression
		replaces
Sebastian Biewer's avatar
Sebastian Biewer committed
861

Sebastian Biewer's avatar
Sebastian Biewer committed
862
863
	computeTypes: (env) ->
		if @expression
Sebastian Biewer's avatar
Sebastian Biewer committed
864
865
866
867
868
869
			try
				type = @expression.computeTypes(env, false)
			catch e
				e.line = @line if not e.line
				e.column = @column if not e.column
				throw e
870
			throw ({message: "Channels can not be sent over channels!", line: @line, column: @column, name: "Type Error"}) if type == CCSTypeChannel
Sebastian Biewer's avatar
Sebastian Biewer committed
871
		super
Sebastian Biewer's avatar
Sebastian Biewer committed
872
			
873
	toString: (mini) -> "#{super}!#{if @expression then "(#{@expression.toString(mini)})" else ""}"
Sebastian Biewer's avatar
Sebastian Biewer committed
874
875
	transferDescription: -> "#{super}#{if @expression then ": " + @expression.evaluate() else ""}"
	copy: -> new CCSOutput(@channel.copy(), (@expression?.copy()))
Sebastian Biewer's avatar
Sebastian Biewer committed
876
877
	

878
879
880
881
882
883



# Note - Mar 19, 2015: Changing strategy from saving all values as string to save value to most specific type possible


Sebastian Biewer's avatar
Sebastian Biewer committed
884
# -- Expression
885
class CCSExpression
Sebastian Biewer's avatar
Sebastian Biewer committed
886
	constructor: (@subExps...) ->			# Expression*
887
888
889
890
891
892
893
894
895
896
897
898
		@_exceptionBuffer = null

	setCodePos: (line, column) ->
		@line = line
		@column = column
		if @_exceptionBuffer
			e = @_exceptionBuffer
			@_exceptionBuffer = null
			e.line = line
			e.column = column
			throw e
		@
Sebastian Biewer's avatar
Sebastian Biewer committed
899
	
Sebastian Biewer's avatar
Sebastian Biewer committed
900
901
	getLeft: -> @subExps[0]
	getRight: -> @subExps[1]
Sebastian Biewer's avatar
Sebastian Biewer committed
902
	applyReplacementDescriptor: (replaces) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
903
		@subExps = ((
Sebastian Biewer's avatar
Sebastian Biewer committed
904
			e.applyReplacementDescriptor(replaces)
Sebastian Biewer's avatar
Sebastian Biewer committed
905
		) for e in @subExps)
Sebastian Biewer's avatar
Sebastian Biewer committed
906
		@
Sebastian Biewer's avatar
Sebastian Biewer committed
907
908
909
910
911
912
	# replaceVariable: (varName, exp) -> 
	# 	@subExps = ((
	# 		e.replaceVariable(varName, exp)
	# 	) for e in @subExps)
	# 	@
	# replaceChannelName: (old, newID) -> null
Sebastian Biewer's avatar
Sebastian Biewer committed
913
	
Sebastian Biewer's avatar
Sebastian Biewer committed
914
	computeTypes: (env, allowsChannel) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
915
916
917
918
919
920
		try
			e.computeTypes(env, false) for e in @subExps
		catch e
			e.line = @line if not e.line
			e.column = @column if not e.column
			throw e
Sebastian Biewer's avatar
Sebastian Biewer committed
921
		CCSTypeValue
922

Sebastian Biewer's avatar
Sebastian Biewer committed
923
924
	evaluate: -> throw new Error("Abstract method!")
	isEvaluatable: -> false
Sebastian Biewer's avatar
Sebastian Biewer committed
925
	typeOfEvaluation: -> throw new Error("Abstract method!")
Sebastian Biewer's avatar
Sebastian Biewer committed
926
		
Sebastian Biewer's avatar
Sebastian Biewer committed
927
928
	needsBracketsForSubExp: (exp) -> 
		@getPrecedence? and exp.getPrecedence? and exp.getPrecedence() < @getPrecedence()
Sebastian Biewer's avatar
Sebastian Biewer committed
929
	stringForSubExp: (exp, mini) ->
Sebastian Biewer's avatar
Sebastian Biewer committed
930
		if @needsBracketsForSubExp exp
Sebastian Biewer's avatar
Sebastian Biewer committed
931
			"(#{exp.toString(mini)})"
Sebastian Biewer's avatar
Sebastian Biewer committed
932
		else
Sebastian Biewer's avatar
Sebastian Biewer committed
933
			"#{exp.toString(mini)}"
Sebastian Biewer's avatar
Sebastian Biewer committed
934
935
936
937
938
	toString: -> throw new Error("Abstract method not implemented!")
	copy: -> throw new Error("Abstract method not implemented!")


# - ConstantExpression
Sebastian Biewer's avatar
Sebastian Biewer committed
939
class CCSConstantExpression extends CCSExpression
Sebastian Biewer's avatar
Sebastian Biewer committed
940
941
	constructor: (@value) -> 
		super()
942
943
944
		if typeof @value == "number" and (@value >= 9007199254740992 or @value <= -9007199254740992)
			@_exceptionBuffer = ({message: "Value exceeds maximum integer bounds: [-9007199254740991 ; 9007199254740991]", line: @line, column: @column, name: "Type Error"})
		
Sebastian Biewer's avatar
Sebastian Biewer committed
945
946
	
	getPrecedence: -> 18
947
	evaluate: -> @value
Sebastian Biewer's avatar
Sebastian Biewer committed
948
	isEvaluatable: -> true
Sebastian Biewer's avatar
Sebastian Biewer committed
949
	typeOfEvaluation: -> typeof @value
950
	toString: -> CCSStringRepresentationForValue @value #if typeof @value == "string" then '"'+@value+'"' else "" + @value
Sebastian Biewer's avatar
Sebastian Biewer committed
951
	copy: -> new CCSConstantExpression(@value)
952
	
Sebastian Biewer's avatar
Sebastian Biewer committed
953

954
955
956
CCSStringRepresentationForValue = (value) ->
	if CCSValueIsInt(value) then "" + value else if value == true then "true" else if value == false then "false" else "\"#{value}\""

957
CCSStringDataForValue = (value) ->
958
959
	# value = (if value == true then "1" else "0") if typeof value == "boolean"
	value = (if value == true then "true" else "false") if typeof value == "boolean"
Sebastian Biewer's avatar
Sebastian Biewer committed
960
	value = "" + value
Sebastian Biewer's avatar
Sebastian Biewer committed
961

962
963
CCSValueIsInt = (value) -> ("" + value).match(/^-?[0-9]+$/)

Sebastian Biewer's avatar
Sebastian Biewer committed
964
CCSBestStringForValue = (value) ->
965
	if CCSValueIsInt(value) then "" + value else if value == true then "1" else if value == false then "0" else "\"#{value}\""
Sebastian Biewer's avatar
Sebastian Biewer committed
966
967

CCSBooleanForString = (string) -> if string == "0" then false else if string == "1" then true else throw new Error("Value #{CCSBestStringForValue string} is not a boolean value!")
Sebastian Biewer's avatar
Sebastian Biewer committed
968
969
	

Sebastian Biewer's avatar
Sebastian Biewer committed
970
# - VariableExpression
Sebastian Biewer's avatar
Sebastian Biewer committed
971
class CCSVariableExpression extends CCSExpression
Sebastian Biewer's avatar
Sebastian Biewer committed
972
973
	constructor: (@variableName) -> 
		super()
Sebastian Biewer's avatar
Sebastian Biewer committed
974
975
		if not @variableName
			throw new Error("Tried to instantiate a variable expression without a variable name!")
Sebastian Biewer's avatar
Sebastian Biewer committed
976
977
	
	getPrecedence: -> 18
Sebastian Biewer's avatar
Sebastian Biewer committed
978
	computeTypes: (env, allowsChannel) -> 		# channel is allowed if cariable expression is root expression of a process application argument
Sebastian Biewer's avatar
Sebastian Biewer committed
979
980
981
982
983
984
985
986
987
988
989
990
		try
			if allowsChannel
				env.setType(@variableName, CCSTypeUnknown)
				env.getType(@variableName)
			else	
				env.getType(@variableName)	# Ensure that the variable is bound
				env.setType(@variableName, CCSTypeValue)	# We have to force type "value"
				super
		catch e
			e.line = @line if not e.line
			e.column = @column if not e.column
			throw e
Sebastian Biewer's avatar
Sebastian Biewer committed
991
	#usesIdentifier: (identifier) -> identifier == @variableName
Sebastian Biewer's avatar
Sebastian Biewer committed
992
993
994
995
	applyReplacementDescriptor: (replaces) ->
		if replaces.variableHasExpressionReplacement(@variableName)
			return replaces.expressionForVariableName(@variableName)
		else if replaces.variableHasChannelReplacement(@variableName)
Sebastian Biewer's avatar
Sebastian Biewer committed
996
			debugger
Sebastian Biewer's avatar
Sebastian Biewer committed
997
998
999
1000
1001
1002
1003
			@variableName = replaces.channelNameForVariableName(@variableName)
		@
		
	# replaceVariable: (varName, exp) -> 
	# 	if varName == @variableName then exp else @
	# replaceChannelName: (old, newID) ->
	# 	@variableName = newID if @variableName == old
1004
1005
	evaluate: -> throw ({message: "Unbound identifier", line: @line, column: @column, name: "Type Error"})
	typeOfEvaluation: -> throw ({message: "Unbound identifier", line: @line, column: @column, name: "Type Error"})
Sebastian Biewer's avatar
Sebastian Biewer committed
1006
1007
1008
	isEvaluatable: -> false
	toString: -> @variableName
	
Sebastian Biewer's avatar
Sebastian Biewer committed
1009
	copy: -> new CCSVariableExpression(@variableName)
Sebastian Biewer's avatar
Sebastian Biewer committed
1010

Sebastian Biewer's avatar
Sebastian Biewer committed
1011

1012
1013
1014
1015
# - ComplementExpression
class CCSComplementExpression extends CCSExpression
	getPrecedence: -> 17
	evaluate: ->
1016
1017
1018
1019
1020
		v = @subExps[0].evaluate()
		if typeof v != "boolean"
			throw ({message: "Complement operand is not a boolean value!", line: @line, column: @column, name: "Type Error"})
		not v
	isEvaluatable: -> @subExps[0].isEvaluatable() and typeof @subExps[0].evaluate() == "boolean"
1021
1022
1023
	typeOfEvaluation: -> "boolean"
	toString: (mini) -> 
		if mini and @isEvaluatable()
1024
			CCSStringRepresentationForValue(@evaluate())
1025
1026
1027
1028
1029
		else
			"!#{@stringForSubExp(@subExps[0], mini)}"
	copy: -> new CCSComplementExpression(@subExps[0].copy())