UNPKG

32 kBtext/coffeescriptView Raw
1
2
3#jmp_buf stop_return, draw_stop_return
4
5# s is a string here
6stop = (s) ->
7 #if (draw_flag == 2)
8 # longjmp(draw_stop_return, 1)
9 #else
10 errorMessage += "Stop: "
11 errorMessage += s
12 #debugger
13 message = errorMessage
14
15 errorMessage = ''
16 moveTos 0
17
18 throw new Error(message)
19
20 #longjmp(stop_return, 1)
21
22# Figuring out dependencies is key to automatically
23# generating a method signature when generating JS code
24# from algebrite scripts.
25# This is important because the user can keep using normal Algebrite
26# scripting without special notations.
27# Basically the process consists of figuring out
28# the "ground variables" that are needed to compute each variable.
29# Now there are two ways of doing this:
30# * at parse time
31# * after running the scripts
32# Doing it at parse time means that we can't track simplifications
33# canceling-out some variables for example. But on the other side
34# it's very quick and the user can somehow see what the signature is
35# going to look like (assuming tha code is rather simple), or anyways
36# is going to easily make sense of the generated signature.
37# Doing it after execution on the other hand would allow us to see
38# if some variable cancel-out. But if variables cancel out then
39# they might do so according to some run-time behaviour that the user
40# might struggle to keep track of.
41# So the effort for the user to make sense of the signature in the first case
42# is similar to the effort of keeping tab of types in a typed language.
43# While in the second case the effort is similar to running the
44# code and simplifications in her head.
45#
46# If we just want to compute the dependencies, we don't need to do
47# anything costly, we don't "run" the code and we don't simplify
48# the code. Just finding the plain dependencies
49# TODO change the name of this function, as it doesn't just find the
50# dependencies. It also runs it and generates the JS code.
51findDependenciesInScript = (stringToBeParsed, dontGenerateCode) ->
52
53 if DEBUG then console.log "stringToBeParsed: " + stringToBeParsed
54
55 timeStartFromAlgebra = new Date().getTime()
56
57 if CACHE_DEBUGS or CACHE_HITSMISS_DEBUGS or TIMING_DEBUGS
58 console.log " --------- findDependenciesInScript input: " + stringToBeParsed + " at: " + (new Date())
59 currentStateHash = getStateHash()
60 console.log "state hash: " + currentStateHash
61
62
63 inited = true
64 codeGen = true
65 symbolsDependencies = {}
66 symbolsHavingReassignments = []
67 symbolsInExpressionsWithoutAssignments = []
68 patternHasBeenFound = false
69 indexOfPartRemainingToBeParsed = 0
70
71 allReturnedPlainStrings = ""
72 allReturnedLatexStrings = ""
73
74 n = 0
75
76 # we are going to store the dependencies _of the block as a whole_
77 # so all affected variables in the whole block are lumped
78 # together, and same for the variable that affect those, we
79 # lump them all together.
80 dependencyInfo =
81 affectsVariables: []
82 affectedBy: []
83
84
85 stringToBeRun = stringToBeParsed
86 if ENABLE_CACHING and stringToBeRun != "clearall"
87 currentStateHash = getStateHash()
88 cacheKey = currentStateHash + " stringToBeRun: " + stringToBeRun + " - " + dontGenerateCode
89 if CACHE_DEBUGS then console.log "cached_findDependenciesInScript key: " + cacheKey
90 possiblyCached = cached_findDependenciesInScript.get(cacheKey)
91 if possiblyCached?
92 if CACHE_HITSMISS_DEBUGS then console.log "cached_findDependenciesInScript hit on " + stringToBeRun
93 unfreeze(possiblyCached)
94 # return the output string
95 if TIMING_DEBUGS
96 totalTime = new Date().getTime() - timeStartFromAlgebra
97 console.log "findDependenciesInScript input: " + stringToBeRun + " time: " + totalTime + "ms, saved " + (possiblyCached[possiblyCached.length-5] - totalTime) + "ms due to cache hit"
98
99 return [
100 possiblyCached[possiblyCached.length - 7],
101 possiblyCached[possiblyCached.length - 6],
102 possiblyCached[possiblyCached.length - 5],
103 possiblyCached[possiblyCached.length - 4],
104 possiblyCached[possiblyCached.length - 3],
105 possiblyCached[possiblyCached.length - 2],
106 possiblyCached[possiblyCached.length - 1]
107 ]
108
109 else
110 if CACHE_HITSMISS_DEBUGS then console.log "cached_findDependenciesInScript miss on: " + stringToBeRun
111 if TIMING_DEBUGS
112 cacheMissPenalty = (new Date().getTime() - timeStartFromAlgebra)
113
114
115 # parse the input. This collects the
116 # dependency information
117 while (1)
118 try
119 errorMessage = ""
120 check_stack()
121 if DEBUG then console.log "findDependenciesInScript: scanning"
122 n = scan(stringToBeParsed.substring(indexOfPartRemainingToBeParsed))
123 if DEBUG then console.log "scanned"
124 pop()
125 check_stack()
126 catch error
127 if PRINTOUTRESULT then console.log error
128 errorMessage = error + ""
129 #debugger
130 reset_after_error()
131 break
132
133 if (n == 0)
134 break
135
136 indexOfPartRemainingToBeParsed += n
137
138 testableString = ""
139
140 # print out all local dependencies as collected by this
141 # parsing pass
142 if DEBUG then console.log "all local dependencies ----------------"
143 testableString += "All local dependencies: "
144 for key, value of symbolsDependencies
145 if DEBUG then console.log "variable " + key + " depends on: "
146 dependencyInfo.affectsVariables.push key
147 testableString += " variable " + key + " depends on: "
148 for i in value
149 if DEBUG then console.log " " + i
150 if i[0] != "'"
151 dependencyInfo.affectedBy.push i
152 testableString += i + ", "
153 testableString += "; "
154 testableString += ". "
155
156 # print out the symbols with re-assignments:
157 if DEBUG then console.log "Symbols with reassignments ----------------"
158 testableString += "Symbols with reassignments: "
159 for key in symbolsHavingReassignments
160 if dependencyInfo.affectedBy.indexOf(key) == -1
161 dependencyInfo.affectedBy.push key
162 testableString += key + ", "
163 testableString += ". "
164
165 # print out the symbols that appear in expressions without assignments
166 if DEBUG then console.log "Symbols in expressions without assignments ----------------"
167 testableString += "Symbols in expressions without assignments: "
168 for key in symbolsInExpressionsWithoutAssignments
169 if dependencyInfo.affectedBy.indexOf(key) == -1
170 dependencyInfo.affectedBy.push key
171 testableString += key + ", "
172 testableString += ". "
173
174 # ALL Algebrite code is affected by any pattern changing
175 dependencyInfo.affectedBy.push "PATTERN_DEPENDENCY"
176
177 if patternHasBeenFound
178 dependencyInfo.affectsVariables.push "PATTERN_DEPENDENCY"
179 testableString += " - PATTERN_DEPENDENCY inserted - "
180
181 # print out all global dependencies as collected by this
182 # parsing pass
183 if DEBUG then console.log "All dependencies recursively ----------------"
184 testableString += "All dependencies recursively: "
185
186 scriptEvaluation = ["",""]
187 generatedCode = ""
188 readableSummaryOfGeneratedCode = ""
189
190 if errorMessage == "" and !dontGenerateCode
191
192 try
193 allReturnedPlainStrings = ""
194 allReturnedLatexStrings = ""
195 scriptEvaluation = run(stringToBeParsed, true)
196 allReturnedPlainStrings = ""
197 allReturnedLatexStrings = ""
198 catch error
199 if PRINTOUTRESULT then console.log error
200 errorMessage = error + ""
201 #debugger
202 init()
203
204 if errorMessage == ""
205 for key of symbolsDependencies
206
207
208 codeGen = true
209 if DEBUG then console.log " variable " + key + " is: " + get_binding(usr_symbol(key)).toString()
210 codeGen = false
211 if DEBUG then console.log " variable " + key + " depends on: "
212 testableString += " variable " + key + " depends on: "
213
214 recursedDependencies = []
215 variablesWithCycles = []
216 cyclesDescriptions = []
217
218 recursiveDependencies key, recursedDependencies, [], variablesWithCycles, [], cyclesDescriptions
219
220 for i in variablesWithCycles
221 if DEBUG then console.log " --> cycle through " + i
222
223 for i in recursedDependencies
224 if DEBUG then console.log " " + i
225 testableString += i + ", "
226 testableString += "; "
227
228 for i in cyclesDescriptions
229 testableString += " " + i + ", "
230
231 if DEBUG then console.log " code generation:" + key + " is: " + get_binding(usr_symbol(key)).toString()
232
233 # we really want to make an extra effort
234 # to generate simplified code, so
235 # run a "simplify" on the content of each
236 # variable that we are generating code for.
237 # Note that the variable
238 # will still point to un-simplified structures,
239 # we only simplify the generated code.
240 push get_binding(usr_symbol(key))
241
242 # Since we go and simplify all variables we meet,
243 # we have to replace each variable passed as a parameter
244 # with something entirely new, so that there is no chance
245 # that it might evoke previous values in the external scope
246 # as in this case:
247 # a = 2
248 # f(a) = a+1+b
249 # we don't want 'a' in the body of f to be simplified to 2
250 # There are two cases: 1) the variable actually was already in
251 # the symbol table, in which case there is going to be this new
252 # one prepended with AVOID_BINDING_TO_EXTERNAL_SCOPE_VALUE, and
253 # we'll have to remove up this variable later.
254 # OR 2) the variable wasn't already in the symbol table, in which
255 # case we directly create this one, which means that we'll have
256 # to rename it later to the correct name without the prepended
257 # part.
258
259 replacementsFrom = []
260 replacementsTo = []
261
262 for eachDependency in recursedDependencies
263 if eachDependency[0] == "'"
264 deQuotedDep = eachDependency.substring(1)
265 originalUserSymbol = usr_symbol(deQuotedDep)
266 newUserSymbol = usr_symbol("AVOID_BINDING_TO_EXTERNAL_SCOPE_VALUE"+deQuotedDep)
267 replacementsFrom.push originalUserSymbol
268 replacementsTo.push newUserSymbol
269 push(originalUserSymbol)
270 push(newUserSymbol)
271 subst()
272 if DEBUG then console.log "after substitution: " + stack[tos-1]
273
274 try
275 simplifyForCodeGeneration()
276 catch error
277 if PRINTOUTRESULT then console.log error
278 errorMessage = error + ""
279 #debugger
280 init()
281
282 for indexOfEachReplacement in [0...replacementsFrom.length]
283 #console.log "replacing back " + replacementsTo[indexOfEachReplacement] + " into: " + replacementsFrom[indexOfEachReplacement]
284 push(replacementsTo[indexOfEachReplacement])
285 push(replacementsFrom[indexOfEachReplacement])
286 subst()
287
288 clearRenamedVariablesToAvoidBindingToExternalScope()
289
290 if errorMessage == ""
291 toBePrinted = pop()
292
293 # we have to get all the variables used on the right side
294 # here. I.e. to print the arguments it's better to look at the
295 # actual method body after simplification.
296 userVariablesMentioned = []
297 collectUserSymbols(toBePrinted, userVariablesMentioned)
298
299 allReturnedPlainStrings = ""
300 allReturnedLatexStrings = ""
301 codeGen = true
302 generatedBody = toBePrinted.toString()
303 codeGen = false
304
305 origPrintMode = printMode
306 printMode = PRINTMODE_LATEX
307
308 bodyForReadableSummaryOfGeneratedCode = toBePrinted.toString()
309
310 printMode = origPrintMode
311
312 if variablesWithCycles.indexOf(key) != -1
313 generatedCode += "// " + key + " is part of a cyclic dependency, no code generated."
314 readableSummaryOfGeneratedCode += "#" + key + " is part of a cyclic dependency, no code generated."
315 else
316
317 ###
318 # using this paragraph instead of the following one
319 # creates methods signatures that
320 # are slightly less efficient
321 # i.e. variables compare even if they are
322 # simplified away.
323 # In theory these signatures are more stable, but
324 # in practice signatures vary quite a bit anyways
325 # depending on previous assignments for example,
326 # so it's unclear whether going for stability
327 # is sensible at all..
328 if recursedDependencies.length != 0
329 parameters = "("
330 for i in recursedDependencies
331 if i.indexOf("'") != 0
332 parameters += i + ", "
333 else
334 if recursedDependencies.indexOf(i.substring(1)) == -1
335 parameters += i.substring(1) + ", "
336 ###
337
338
339 # remove all native functions from the
340 # parameters as well.
341 userVariablesMentioned = userVariablesMentioned.filter (x) ->
342 predefinedSymbolsInGlobalScope_doNotTrackInDependencies.indexOf(x + "") == -1
343
344 # remove the variable that are not in the dependency list
345 # i.e. only allow the variables that are in the dependency list
346 userVariablesMentioned = userVariablesMentioned.filter (x) ->
347 recursedDependencies.indexOf(x + "") != -1 or
348 recursedDependencies.indexOf("\'" + x + "") != -1
349
350 if userVariablesMentioned.length != 0
351 parameters = "("
352 for i in userVariablesMentioned
353 if i.printname != key
354 parameters += i.printname + ", "
355
356 # eliminate the last ", " for printout clarity
357 parameters = parameters.replace /, $/gm , ""
358 parameters += ")"
359 generatedCode += key + " = function " + parameters + " { return ( " + generatedBody + " ); }"
360 readableSummaryOfGeneratedCode += key + parameters + " = " + bodyForReadableSummaryOfGeneratedCode
361 else
362 generatedCode += key + " = " + generatedBody + ";"
363 readableSummaryOfGeneratedCode += key + " = " + bodyForReadableSummaryOfGeneratedCode
364
365 generatedCode += "\n"
366 readableSummaryOfGeneratedCode += "\n"
367
368 if DEBUG then console.log " " + generatedCode
369
370 # eliminate the last new line
371 generatedCode = generatedCode.replace /\n$/gm , ""
372 readableSummaryOfGeneratedCode = readableSummaryOfGeneratedCode.replace /\n$/gm , ""
373
374
375 # cleanup
376 symbolsDependencies = {}
377 symbolsHavingReassignments = []
378 patternHasBeenFound = false
379 symbolsInExpressionsWithoutAssignments = []
380
381 if DEBUG then console.log "testable string: " + testableString
382
383 if TIMING_DEBUGS
384 console.log "findDependenciesInScript time for: " + stringToBeRun + " : "+ ((new Date().getTime()) - timeStartFromAlgebra) + "ms"
385
386 if ENABLE_CACHING and stringToBeRun != "clearall" and errorMessage == ""
387 frozen = freeze()
388 toBeFrozen = [
389 frozen[0],
390 frozen[1],
391 frozen[2],
392 frozen[3],
393 frozen[4],
394 frozen[5],
395 (new Date().getTime() - timeStartFromAlgebra),
396 testableString,
397 scriptEvaluation[0],
398 generatedCode,
399 readableSummaryOfGeneratedCode,
400 scriptEvaluation[1],
401 errorMessage,
402 dependencyInfo
403 ]
404 if CACHE_DEBUGS then console.log "setting cached_findDependenciesInScript on key: " + cacheKey
405 cached_findDependenciesInScript.set(cacheKey, toBeFrozen)
406
407
408 return [testableString, scriptEvaluation[0], generatedCode, readableSummaryOfGeneratedCode, scriptEvaluation[1], errorMessage, dependencyInfo]
409
410recursiveDependencies = (variableToBeChecked, arrayWhereDependenciesWillBeAdded, variablesAlreadyFleshedOut, variablesWithCycles, chainBeingChecked, cyclesDescriptions) ->
411 variablesAlreadyFleshedOut.push variableToBeChecked
412
413 # recursive dependencies can only be descended if the variable is not bound to a parameter
414 if symbolsDependencies[chainBeingChecked[chainBeingChecked.length-1]]?
415 if symbolsDependencies[chainBeingChecked[chainBeingChecked.length-1]].indexOf("'"+variableToBeChecked) != -1
416 if DEBUG then console.log "can't keep following the chain of " + variableToBeChecked + " because it's actually a variable bound to a parameter"
417 if arrayWhereDependenciesWillBeAdded.indexOf("'"+variableToBeChecked) == -1 and arrayWhereDependenciesWillBeAdded.indexOf(variableToBeChecked) == -1
418 arrayWhereDependenciesWillBeAdded.push variableToBeChecked
419 return arrayWhereDependenciesWillBeAdded
420
421 chainBeingChecked.push variableToBeChecked
422
423 if !symbolsDependencies[variableToBeChecked]?
424 # end case: the passed variable has no dependencies
425 # so there is nothing else to do
426 if arrayWhereDependenciesWillBeAdded.indexOf(variableToBeChecked) == -1
427 arrayWhereDependenciesWillBeAdded.push variableToBeChecked
428 return arrayWhereDependenciesWillBeAdded
429 else
430 # recursion case: we have to dig deeper
431 for i in symbolsDependencies[variableToBeChecked]
432
433 # check that there is no recursion in dependencies
434 # we do that by keeping a list of variables that
435 # have already been "fleshed-out". If we encounter
436 # any of those "fleshed-out" variables while
437 # fleshing out, then there is a cycle
438
439 if chainBeingChecked.indexOf(i) != -1
440 if DEBUG then console.log " found cycle:"
441 cyclesDescription = ""
442 for k in chainBeingChecked
443 if variablesWithCycles.indexOf(k) == -1
444 variablesWithCycles.push k
445 if DEBUG then console.log k + " --> "
446 cyclesDescription += k + " --> "
447 if DEBUG then console.log " ... then " + i + " again"
448 cyclesDescription += " ... then " + i + " again"
449 cyclesDescriptions.push cyclesDescription
450 #if DEBUG then console.log " --> cycle through " + i
451 # we want to flesh-out i but it's already been
452 # fleshed-out, just add it to the variables
453 # with cycles and move on
454 # todo refactor this, there are two copies of these two lines
455 if variablesWithCycles.indexOf(i) == -1
456 variablesWithCycles.push i
457 else
458 # flesh-out i recursively
459 recursiveDependencies i, arrayWhereDependenciesWillBeAdded, variablesAlreadyFleshedOut, variablesWithCycles, chainBeingChecked, cyclesDescriptions
460 chainBeingChecked.pop()
461 #variablesAlreadyFleshedOut.pop()
462
463 return arrayWhereDependenciesWillBeAdded
464
465
466
467# parses and runs one statement/expression at a time
468inited = false
469
470latexErrorSign = "\\rlap{\\large\\color{red}\\bigtriangleup}{\\ \\ \\tiny\\color{red}!}"
471turnErrorMessageToLatex = (theErrorMessage) ->
472 theErrorMessage = theErrorMessage.replace(/\n/g,"")
473 theErrorMessage = theErrorMessage.replace(/_/g, "} \\_ \\text{");
474 theErrorMessage = theErrorMessage.replace(new RegExp(String.fromCharCode(transpose_unicode), 'g'), "}{}^{T}\\text{");
475 theErrorMessage = theErrorMessage.replace(new RegExp(String.fromCharCode(dotprod_unicode), 'g'),"}\\cdot \\text{");
476 theErrorMessage = theErrorMessage.replace("Stop:","} \\quad \\text{Stop:");
477 theErrorMessage = theErrorMessage.replace("->","} \\rightarrow \\text{");
478 theErrorMessage = theErrorMessage.replace("?","}\\enspace " + latexErrorSign + " \\enspace \\text{");
479 theErrorMessage = "$$\\text{" + theErrorMessage.replace(/\n/g,"") + "}$$"
480 #console.log "theErrorMessage: " + theErrorMessage
481 return theErrorMessage
482
483# there are around a dozen different unicodes that
484# represent some sort of middle dot, let's catch the most
485# common and turn them into what we can process
486normaliseDots = (stringToNormalise) ->
487 stringToNormalise = stringToNormalise.replace(new RegExp(String.fromCharCode(8901), 'g'), String.fromCharCode(dotprod_unicode));
488 stringToNormalise = stringToNormalise.replace(new RegExp(String.fromCharCode(8226), 'g'), String.fromCharCode(dotprod_unicode));
489 stringToNormalise = stringToNormalise.replace(new RegExp(String.fromCharCode(12539), 'g'), String.fromCharCode(dotprod_unicode));
490 stringToNormalise = stringToNormalise.replace(new RegExp(String.fromCharCode(55296), 'g'), String.fromCharCode(dotprod_unicode));
491 stringToNormalise = stringToNormalise.replace(new RegExp(String.fromCharCode(65381), 'g'), String.fromCharCode(dotprod_unicode));
492 return stringToNormalise
493
494
495CACHE_DEBUGS = false
496CACHE_HITSMISS_DEBUGS = false
497TIMING_DEBUGS = false
498
499cacheMissPenalty = 0
500
501run = (stringToBeRun, generateLatex = false) ->
502
503 timeStart = new Date().getTime()
504
505 #stringToBeRun = stringToBeRun + "\n"
506 stringToBeRun = normaliseDots stringToBeRun
507 #console.log "run running: " + stringToBeRun
508
509 if ENABLE_CACHING and stringToBeRun != "clearall"
510 currentStateHash = getStateHash()
511 cacheKey = currentStateHash + " stringToBeRun: " + stringToBeRun
512 if CACHE_DEBUGS then console.log "cached_runs key: " + cacheKey
513 possiblyCached = cached_runs.get(cacheKey)
514 #possiblyCached = null
515 if possiblyCached?
516 if CACHE_HITSMISS_DEBUGS then console.log "cached_runs hit on: " + stringToBeRun
517 unfreeze(possiblyCached)
518 # return the output string
519 if TIMING_DEBUGS
520 totalTime = new Date().getTime() - timeStart
521 console.log "run time: " + totalTime + "ms, saved " + (possiblyCached[possiblyCached.length-2] - totalTime) + "ms due to cache hit"
522 return possiblyCached[possiblyCached.length - 1]
523 else
524 if CACHE_HITSMISS_DEBUGS then console.log "cached_runs miss on: " + stringToBeRun
525 if TIMING_DEBUGS
526 cacheMissPenalty = (new Date().getTime() - timeStart)
527
528 if stringToBeRun == "selftest"
529 selftest()
530 return
531
532 #if (setjmp(stop_return))
533 # return
534
535 if !inited
536 inited = true
537 init()
538
539 i = 0
540 n = 0
541 indexOfPartRemainingToBeParsed = 0
542
543 allReturnedPlainStrings = ""
544 allReturnedLatexStrings = ""
545
546 while (1)
547 # while we can keep scanning commands out of the
548 # passed input AND we can execute them...
549
550 try
551 errorMessage = ""
552 check_stack()
553 n = scan(stringToBeRun.substring(indexOfPartRemainingToBeParsed))
554 p1 = pop()
555 check_stack()
556 catch error
557 if PRINTOUTRESULT then console.log error
558 #debugger
559 allReturnedPlainStrings += error.message
560 if generateLatex
561 #debugger
562 theErrorMessage = turnErrorMessageToLatex error.message
563 allReturnedLatexStrings += theErrorMessage
564 reset_after_error()
565
566 break
567
568
569
570 if (n == 0)
571 break
572
573 # if debug mode then print the source text
574
575 #if (equaln(get_binding(symbol(TRACE)), 1)) {
576 # for (i = 0 i < n i++)
577 # if (s[i] != '\r')
578 # printchar(s[i])
579 # if (s[n - 1] != '\n') # n is not zero, see above
580 # printchar('\n')
581 #}
582
583 indexOfPartRemainingToBeParsed += n
584
585 push(p1)
586 #debugger
587 errorWhileExecution = false
588 try
589 stringsEmittedByUserPrintouts = ""
590 top_level_eval()
591 #console.log "emitted string after top_level_eval(): >" + stringsEmittedByUserPrintouts + "<"
592 #console.log "allReturnedPlainStrings string after top_level_eval(): >" + allReturnedPlainStrings + "<"
593
594 p2 = pop()
595 check_stack()
596
597 if (isstr(p2))
598 if DEBUG then console.log(p2.str)
599 if DEBUG then console.log("\n")
600
601 # if the return value is nil there isn't much point
602 # in adding "nil" to the printout
603 if (p2 == symbol(NIL))
604 #collectedPlainResult = stringsEmittedByUserPrintouts
605 collectedPlainResult = stringsEmittedByUserPrintouts
606 if generateLatex
607 collectedLatexResult = "$$" + stringsEmittedByUserPrintouts + "$$"
608 else
609 #console.log "emitted string before collectPlainStringFromReturnValue: >" + stringsEmittedByUserPrintouts + "<"
610 #console.log "allReturnedPlainStrings string before collectPlainStringFromReturnValue: >" + allReturnedPlainStrings + "<"
611 collectedPlainResult = print_expr(p2)
612 collectedPlainResult += "\n"
613 #console.log "collectedPlainResult: >" + collectedPlainResult + "<"
614 if generateLatex
615 collectedLatexResult = "$$" + collectLatexStringFromReturnValue(p2) + "$$"
616 if DEBUG then console.log "collectedLatexResult: " + collectedLatexResult
617
618 allReturnedPlainStrings += collectedPlainResult
619 if generateLatex then allReturnedLatexStrings += collectedLatexResult
620
621 if PRINTOUTRESULT
622 if DEBUG then console.log "printline"
623 if DEBUG then console.log collectedPlainResult
624 #alert collectedPlainResult
625 if PRINTOUTRESULT
626 if DEBUG then console.log "display:"
627 print2dascii(p2)
628
629 if generateLatex then allReturnedLatexStrings += "\n"
630
631 catch error
632 errorWhileExecution = true
633 collectedPlainResult = error.message
634 if generateLatex then collectedLatexResult = turnErrorMessageToLatex error.message
635
636 if PRINTOUTRESULT then console.log collectedPlainResult
637
638 allReturnedPlainStrings += collectedPlainResult
639 if collectedPlainResult != ""
640 allReturnedPlainStrings += "\n"
641
642 if generateLatex
643 allReturnedLatexStrings += collectedLatexResult
644 allReturnedLatexStrings += "\n"
645
646 resetCache()
647 init()
648
649 if allReturnedPlainStrings[allReturnedPlainStrings.length-1] == "\n"
650 allReturnedPlainStrings = allReturnedPlainStrings.substring(0,allReturnedPlainStrings.length-1)
651
652 if generateLatex
653 if allReturnedLatexStrings[allReturnedLatexStrings.length-1] == "\n"
654 allReturnedLatexStrings = allReturnedLatexStrings.substring(0,allReturnedLatexStrings.length-1)
655
656 if generateLatex
657 if DEBUG then console.log "allReturnedLatexStrings: " + allReturnedLatexStrings
658 # TODO handle this case of caching
659 stringToBeReturned = [allReturnedPlainStrings, allReturnedLatexStrings]
660 else
661 stringToBeReturned = allReturnedPlainStrings
662
663 if ENABLE_CACHING and stringToBeRun != "clearall" and !errorWhileExecution
664 frozen = freeze()
665 toBeFrozen = [frozen[0], frozen[1], frozen[2], frozen[3], frozen[4], frozen[5], (new Date().getTime() - timeStart), stringToBeReturned]
666 if CACHE_DEBUGS then console.log "setting cached_runs on key: " + cacheKey
667 cached_runs.set(cacheKey, toBeFrozen)
668
669 if TIMING_DEBUGS
670 timingDebugWrite = "run time on: " + stringToBeRun + " : " + (new Date().getTime() - timeStart) + "ms"
671 if ENABLE_CACHING and stringToBeRun != "clearall" then timingDebugWrite += ", of which cache miss penalty: " + cacheMissPenalty + "ms"
672 console.log timingDebugWrite
673
674 allReturnedPlainStrings = ""
675 allReturnedLatexStrings = ""
676 return stringToBeReturned
677
678check_stack = ->
679 if (tos != 0)
680 debugger
681 stop("stack error")
682 if (frame != TOS)
683 debugger
684 stop("frame error")
685 if chainOfUserSymbolsNotFunctionsBeingEvaluated.length != 0
686 debugger
687 stop("symbols evaluation still ongoing?")
688 if evaluatingAsFloats != 0
689 debugger
690 stop("numeric evaluation still ongoing?")
691 if evaluatingPolar != 0
692 debugger
693 stop("evaluation of polar still ongoing?")
694
695# cannot reference symbols yet
696
697# returns nil on stack if no result to print
698
699top_level_eval = ->
700 if DEBUG then console.log "#### top level eval"
701 save()
702
703 trigmode = 0
704
705 p1 = symbol(AUTOEXPAND)
706
707 if (iszero(get_binding(p1)))
708 expanding = 0
709 else
710 expanding = 1
711
712 p1 = pop()
713 push(p1)
714 Eval()
715 p2 = pop()
716
717 # "draw", "for" and "setq" return "nil", there is no result to print
718
719 if (p2 == symbol(NIL))
720 push(p2)
721 restore()
722 return
723
724 # update "last" to contain the last result
725 set_binding(symbol(LAST), p2)
726
727 if (!iszero(get_binding(symbol(BAKE))))
728 push(p2)
729 bake()
730 p2 = pop()
731
732 # If we evaluated the symbol "i" or "j" and the result was sqrt(-1)
733 # then don't do anything.
734 # Otherwise if "j" is an imaginary unit then subst.
735 # Otherwise if "i" is an imaginary unit then subst.
736 if ((p1 == symbol(SYMBOL_I) || p1 == symbol(SYMBOL_J)) && isimaginaryunit(p2))
737 doNothing = 0
738 else if (isimaginaryunit(get_binding(symbol(SYMBOL_J))))
739 push(p2)
740 push(imaginaryunit)
741 push_symbol(SYMBOL_J)
742 subst()
743 p2 = pop()
744 else if (isimaginaryunit(get_binding(symbol(SYMBOL_I))))
745 push(p2)
746 push(imaginaryunit)
747 push_symbol(SYMBOL_I)
748 subst()
749 p2 = pop()
750
751 #ifndef LINUX ----------------------
752
753 # if we evaluated the symbol "a" and got "b" then print "a=b"
754
755 # do not print "a=a"
756
757 #if (issymbol(p1) && !iskeyword(p1) && p1 != p2 && test_flag == 0)
758 # push_symbol(SETQ)
759 # push(p1)
760 # push(p2)
761 # list(3)
762 # p2 = pop()
763 #endif -----------------------------
764
765 push(p2)
766
767 restore()
768
769check_esc_flag = ->
770 if (esc_flag)
771 stop("esc key")
772
773# this is called when the whole notebook is re-run
774# so we get the chance of clearing the whole state from
775# scratch.
776# In practice, the state we need to clear that persists
777# across blocks are only the patterns, so
778# just eject those.
779clearAlgebraEnvironment = ->
780 #console.log "CLEARING clearAlgebraEnvironment ============================================================="
781 do_clearall()
782
783computeDependenciesFromAlgebra = (codeFromAlgebraBlock) ->
784 if DEBUG then console.log "computeDependenciesFromAlgebra!!!"
785 # return findDependenciesInScript(codeFromAlgebraBlock, true)[6]
786
787 # TODO this part below is duplicated from computeResultsAndJavaScriptFromAlgebra
788 # ...should refactor.
789 originalcodeFromAlgebraBlock = codeFromAlgebraBlock
790 keepState = true
791 called_from_Algebra_block = true
792
793 #console.log "codeFromAlgebraBlock: " + codeFromAlgebraBlock
794
795 codeFromAlgebraBlock = normaliseDots codeFromAlgebraBlock
796
797 if !keepState
798 userSimplificationsInListForm = []
799 userSimplificationsInProgramForm = ""
800 for i in userSimplificationsInListForm
801 #console.log "silentpattern(" + car(i) + ","+cdr(i)+")"
802 userSimplificationsInProgramForm += "silentpattern(" + car(i) + ","+ car(cdr(i)) + "," + car(cdr(cdr(i))) + ")\n"
803
804 do_clearall()
805 codeFromAlgebraBlock = userSimplificationsInProgramForm + codeFromAlgebraBlock
806 if DEBUG then console.log "codeFromAlgebraBlock including patterns: " + codeFromAlgebraBlock
807
808 if DEBUG
809 console.log "computeDependenciesFromAlgebra: patterns in the list --------------- "
810 for i in userSimplificationsInListForm
811 console.log car(i) + ","+cdr(i)+")"
812 console.log "...end of list --------------- "
813
814
815 called_from_Algebra_block = false
816
817 return findDependenciesInScript(codeFromAlgebraBlock, true)[6]
818
819computeResultsAndJavaScriptFromAlgebra = (codeFromAlgebraBlock) ->
820
821
822 originalcodeFromAlgebraBlock = codeFromAlgebraBlock
823 keepState = true
824 called_from_Algebra_block = true
825
826 timeStartFromAlgebra = new Date().getTime()
827
828 if TIMING_DEBUGS
829 console.log " --------- computeResultsAndJavaScriptFromAlgebra input: " + codeFromAlgebraBlock + " at: " + (new Date())
830
831 # we start "clean" each time:
832 # clear all the symbols and then re-define
833 # the "starting" symbols.
834
835 #console.log "codeFromAlgebraBlock: " + codeFromAlgebraBlock
836
837 codeFromAlgebraBlock = normaliseDots codeFromAlgebraBlock
838
839
840
841 stringToBeRun = codeFromAlgebraBlock
842
843 if DEBUG
844 console.log "computeResultsAndJavaScriptFromAlgebra: patterns in the list --------------- "
845 for i in userSimplificationsInListForm
846 console.log car(i) + ","+cdr(i)+")"
847 console.log "...end of list --------------- "
848
849 if !keepState
850 userSimplificationsInListForm = []
851 userSimplificationsInProgramForm = ""
852 for i in userSimplificationsInListForm
853 #console.log "silentpattern(" + car(i) + ","+cdr(i)+")"
854 userSimplificationsInProgramForm += "silentpattern(" + car(i) + ","+ car(cdr(i)) + "," + car(cdr(cdr(i))) + ")\n"
855
856 do_clearall()
857 codeFromAlgebraBlock = userSimplificationsInProgramForm + codeFromAlgebraBlock
858 if DEBUG then console.log "codeFromAlgebraBlock including patterns: " + codeFromAlgebraBlock
859
860 #debugger
861 [testableStringIsIgnoredHere,result,code,readableSummaryOfCode, latexResult, errorMessage, dependencyInfo] =
862 findDependenciesInScript(codeFromAlgebraBlock)
863
864 called_from_Algebra_block = false
865
866 if readableSummaryOfCode != "" or errorMessage != ""
867 result += "\n" + readableSummaryOfCode
868 if errorMessage != ""
869 result += "\n" + errorMessage
870 result = result.replace /\n/g,"\n\n"
871
872 latexResult += "\n" + "$$" + readableSummaryOfCode + "$$"
873 if errorMessage != ""
874 latexResult += turnErrorMessageToLatex errorMessage
875 latexResult = latexResult.replace /\n/g,"\n\n"
876
877 # remove empty results altogether from latex output, which happens
878 # for example for assignments to variables or
879 # functions definitions
880 latexResult = latexResult.replace /\n*/,""
881 latexResult = latexResult.replace /\$\$\$\$\n*/g,""
882
883 code = code.replace /Math\./g,""
884 code = code.replace /\n/g,"\n\n"
885
886 #console.log "code: " + code
887 #console.log "result: " + result
888 #console.log "latexResult: " + latexResult
889
890 if TIMING_DEBUGS
891 console.log "computeResultsAndJavaScriptFromAlgebra time (total time from notebook and back) for: " + stringToBeRun + " : "+ ((new Date().getTime()) - timeStartFromAlgebra) + "ms"
892
893 #code: "// no code generated yet\n//try again later"
894 #code: "console.log('some passed code is run'); window.something = 1;"
895 code: code
896
897 # TODO temporarily pass latex in place of standard result too
898 result: latexResult
899 latexResult: latexResult
900 dependencyInfo: dependencyInfo
901
902enableCaching = ->
903 ENABLE_CACHING = true
904
905disableCaching = ->
906 ENABLE_CACHING = false
907
908(exports ? this).run = run
909(exports ? this).findDependenciesInScript = findDependenciesInScript
910(exports ? this).computeDependenciesFromAlgebra = computeDependenciesFromAlgebra
911(exports ? this).computeResultsAndJavaScriptFromAlgebra = computeResultsAndJavaScriptFromAlgebra
912(exports ? this).clearAlgebraEnvironment = clearAlgebraEnvironment
913(exports ? this).enableCaching = enableCaching
914(exports ? this).disableCaching = disableCaching