UNPKG

21.7 kBtext/coffeescriptView Raw
1# This scanner uses the recursive descent method.
2#
3# The char pointers token_str and scan_str are pointers to the input string as
4# in the following example.
5#
6# | g | a | m | m | a | | a | l | p | h | a |
7# ^ ^
8# token_str scan_str
9#
10# The char pointer token_buf points to a malloc buffer.
11#
12# | g | a | m | m | a | \0 |
13# ^
14# token_buf
15#
16# In the sequence of method invocations for scanning,
17# first we do the calls for scanning the operands
18# of the operators of least precedence.
19# So, since precedence in maths goes something like
20# (form high to low) exponents, mult/div, plus/minus
21# so we scan first for terms, then factors, then powers.
22# That's the general idea, but of course we also have to deal
23# with things like parens, non-commutative
24# dot (or inner) product, assignments and tests,
25# function calls etc.
26# Note that a^1/2 is, correctly, a/2, not, incorrectly, sqrt(a),
27# see comment in related test in power.coffee for more about this.
28
29# Notes:
30#
31# Formerly add() and multiply() were used to construct expressions but
32# this preevaluation caused problems.
33#
34# For example, suppose A has the floating point value inf.
35#
36# Before, the expression A/A resulted in 1 because the scanner would
37# divide the symbols.
38#
39# After removing add() and multiply(), A/A results in nan which is the
40# correct result.
41#
42# The functions negate() and inverse() are used but they do not cause
43# problems with preevaluation of symbols.
44
45
46T_INTEGER = 1001
47T_DOUBLE = 1002
48T_SYMBOL = 1003
49T_FUNCTION = 1004
50T_NEWLINE = 1006
51T_STRING = 1007
52T_GTEQ = 1008
53T_LTEQ = 1009
54T_EQ = 1010
55T_NEQ = 1011
56T_QUOTASSIGN = 1012
57
58token = ""
59newline_flag = 0
60meta_mode = 0
61
62input_str = 0
63scan_str = 0
64token_str = 0
65token_buf = 0
66
67lastFoundSymbol = null
68symbolsRightOfAssignment = null
69symbolsLeftOfAssignment = null
70isSymbolLeftOfAssignment = null
71scanningParameters = null
72functionInvokationsScanningStack = null
73skipRootVariableToBeSolved = false
74assignmentFound = null
75
76
77# Returns number of chars scanned and expr on stack.
78
79# Returns zero when nothing left to scan.
80
81# takes a string
82
83scanned = ""
84scan = (s) ->
85 if DEBUG then console.log "#### scanning " + s
86 #if s=="y=x"
87 # debugger
88 #if s=="y"
89 # debugger
90 #if s=="i=sqrt(-1)"
91 # debugger
92
93 lastFoundSymbol = null
94 symbolsRightOfAssignment = []
95 symbolsLeftOfAssignment = []
96 isSymbolLeftOfAssignment = true
97 scanningParameters = []
98 functionInvokationsScanningStack = [""]
99 assignmentFound = false
100
101
102 scanned = s
103 meta_mode = 0
104 expanding++
105 input_str = 0
106 scan_str = 0
107 get_next_token()
108 if (token == "")
109 push(symbol(NIL))
110 expanding--
111 return 0
112 scan_stmt()
113 expanding--
114
115 if !assignmentFound
116 symbolsInExpressionsWithoutAssignments = symbolsInExpressionsWithoutAssignments.concat symbolsLeftOfAssignment
117
118 return token_str - input_str
119
120# takes a string
121scan_meta = (s) ->
122 scanned = s
123 meta_mode = 1
124 expanding++
125 input_str = 0
126 scan_str = 0
127 get_next_token()
128 if (token == "")
129 push(symbol(NIL))
130 expanding--
131 return 0
132 scan_stmt()
133 expanding--
134 return token_str - input_str
135
136scan_stmt = ->
137 scan_relation()
138
139 assignmentIsOfQuotedType = false
140
141 if token == T_QUOTASSIGN
142 assignmentIsOfQuotedType = true
143
144 if (token == T_QUOTASSIGN or token == '=')
145 symbolLeftOfAssignment = lastFoundSymbol
146 if DEBUG then console.log("assignment!")
147 assignmentFound = true
148 isSymbolLeftOfAssignment = false
149
150 get_next_token()
151 push_symbol(SETQ)
152 swap()
153
154 # if it's a := then add a quote
155 if (assignmentIsOfQuotedType)
156 push_symbol(QUOTE)
157
158 scan_relation()
159
160 # if it's a := then you have to list
161 # together the quote and its argument
162 if assignmentIsOfQuotedType
163 list(2)
164
165 list(3)
166
167 isSymbolLeftOfAssignment = true
168
169 if codeGen
170
171 # in case of re-assignment, the symbol on the
172 # left will also be in the set of the symbols
173 # on the right. In that case just remove it from
174 # the symbols on the right.
175 indexOfSymbolLeftOfAssignment = symbolsRightOfAssignment.indexOf(symbolLeftOfAssignment)
176 if indexOfSymbolLeftOfAssignment != -1
177 symbolsRightOfAssignment.splice(indexOfSymbolLeftOfAssignment, 1)
178 symbolsHavingReassignments.push symbolLeftOfAssignment
179
180 # print out the immediate dependencies
181 if DEBUG
182 console.log "locally, " + symbolLeftOfAssignment + " depends on: "
183 for i in symbolsRightOfAssignment
184 console.log " " + i
185
186 # ok add the local dependencies to the existing
187 # dependencies of this left-value symbol
188
189 # create the exiting dependencies list if it doesn't exist
190 symbolsDependencies[symbolLeftOfAssignment] ?= []
191 existingDependencies = symbolsDependencies[symbolLeftOfAssignment]
192
193 # copy over the new dependencies to the existing
194 # dependencies avoiding repetitions
195 for i in symbolsRightOfAssignment
196 if existingDependencies.indexOf(i) == -1
197 existingDependencies.push i
198
199 symbolsRightOfAssignment = []
200
201scan_relation = ->
202 scan_expression()
203 switch (token)
204 when T_EQ
205 push_symbol(TESTEQ)
206 swap()
207 get_next_token()
208 scan_expression()
209 list(3)
210 when T_NEQ
211 push_symbol(NOT)
212 swap()
213 push_symbol(TESTEQ)
214 swap()
215 get_next_token()
216 scan_expression()
217 list(3)
218 list(2)
219 when T_LTEQ
220 push_symbol(TESTLE)
221 swap()
222 get_next_token()
223 scan_expression()
224 list(3)
225 when T_GTEQ
226 push_symbol(TESTGE)
227 swap()
228 get_next_token()
229 scan_expression()
230 list(3)
231 when '<'
232 push_symbol(TESTLT)
233 swap()
234 get_next_token()
235 scan_expression()
236 list(3)
237 when '>'
238 push_symbol(TESTGT)
239 swap()
240 get_next_token()
241 scan_expression()
242 list(3)
243
244scan_expression = ->
245 h = tos
246 switch token
247 when '+'
248 get_next_token()
249 scan_term()
250 when '-'
251 get_next_token()
252 scan_term()
253 negate()
254 else
255 scan_term()
256
257 while (newline_flag == 0 && (token == '+' || token == '-'))
258 if (token == '+')
259 get_next_token()
260 scan_term()
261 else
262 get_next_token()
263 scan_term()
264 negate()
265
266 if (tos - h > 1)
267 list(tos - h)
268 push_symbol(ADD)
269 swap()
270 cons()
271
272is_factor = ->
273
274 if token.charCodeAt?(0) == dotprod_unicode
275 return 1
276
277 switch (token)
278 when '*', '/'
279 return 1
280 when '(', T_SYMBOL, T_FUNCTION, T_INTEGER, T_DOUBLE, T_STRING
281 if (newline_flag) # implicit mul can't cross line
282 scan_str = token_str # better error display
283 return 0
284 else
285 return 1
286 return 0
287
288
289simplify_1_in_products = (tos,h) ->
290 if (tos > h && isrational(stack[tos - 1]) && equaln(stack[tos - 1], 1))
291 pop()
292
293# calculate away consecutive constants
294multiply_consecutive_constants = (tos,h)->
295 if (tos > h + 1 && isnum(stack[tos - 2]) && isnum(stack[tos - 1]))
296 multiply()
297
298
299scan_term = ->
300 h = tos
301
302 scan_factor()
303
304 if parse_time_simplifications
305 simplify_1_in_products(tos,h)
306
307 while (is_factor())
308 if (token == '*')
309 get_next_token()
310 scan_factor()
311 else if (token == '/')
312 # in case of 1/... then
313 # we scanned the 1, we get rid
314 # of it because otherwise it becomes
315 # an extra factor that wasn't there and
316 # things like
317 # 1/(2*a) become 1*(1/(2*a))
318 simplify_1_in_products(tos,h)
319 get_next_token()
320 scan_factor()
321 inverse()
322 else if (token.charCodeAt?(0) == dotprod_unicode)
323 get_next_token()
324 push_symbol(INNER)
325 swap()
326 scan_factor()
327 list(3)
328
329 else
330 scan_factor()
331
332 if parse_time_simplifications
333 multiply_consecutive_constants(tos,h)
334 simplify_1_in_products(tos,h)
335
336 if (h == tos)
337 push_integer(1)
338 else if (tos - h > 1)
339 list(tos - h)
340 push_symbol(MULTIPLY)
341 swap()
342 cons()
343
344scan_power = ->
345 if (token == '^')
346 get_next_token()
347 push_symbol(POWER)
348 swap()
349 scan_factor()
350 list(3)
351
352scan_index = (h) ->
353 #console.log "[ as index"
354 get_next_token()
355 push_symbol(INDEX)
356 swap()
357 scan_expression()
358 while (token == ',')
359 get_next_token()
360 scan_expression()
361 if (token != ']')
362 scan_error("] expected")
363 get_next_token()
364 list(tos - h)
365
366
367scan_factor = ->
368
369 h = tos
370
371 #console.log "scan_factor token: " + token
372
373 firstFactorIsNumber = false
374
375 if (token == '(')
376 scan_subexpr()
377 else if (token == T_SYMBOL)
378 scan_symbol()
379 else if (token == T_FUNCTION)
380 scan_function_call_with_function_name()
381 else if token == '['
382 #console.log "[ as tensor"
383 #debugger
384 scan_tensor()
385 else if (token == T_INTEGER)
386 firstFactorIsNumber = true
387 bignum_scan_integer(token_buf)
388 get_next_token()
389 else if (token == T_DOUBLE)
390 firstFactorIsNumber = true
391 bignum_scan_float(token_buf)
392 get_next_token()
393 else if (token == T_STRING)
394 scan_string()
395 else
396 scan_error("syntax error")
397
398
399 # after the main initial part of the factor that
400 # we just scanned above,
401 # we can get an arbitrary about of appendages
402 # of the form ...[...](...)...
403 # If the main part is not a number, then these are all, respectively,
404 # - index references (as opposed to tensor definition) and
405 # - function calls without an explicit function name
406 # (instead of subexpressions or parameters of function
407 # definitions or function calls with an explicit function
408 # name), respectively
409 while token == '[' or token == '(' and newline_flag == 0 and !firstFactorIsNumber
410 if token == '['
411 scan_index(h)
412 else if token == '('
413 #console.log "( as function call without function name "
414 scan_function_call_without_function_name()
415
416
417
418 while (token == '!')
419 get_next_token()
420 push_symbol(FACTORIAL)
421 swap()
422 list(2)
423
424 # in theory we could already count the
425 # number of transposes and simplify them
426 # away, but it's not that clean to have
427 # multiple places where that happens, and
428 # the parser is not the place.
429 while (token.charCodeAt?(0) == transpose_unicode)
430 get_next_token()
431 push_symbol(TRANSPOSE)
432 swap()
433 list(2)
434
435 scan_power()
436
437
438addSymbolRightOfAssignment = (theSymbol) ->
439 if predefinedSymbolsInGlobalScope_doNotTrackInDependencies.indexOf(theSymbol) == -1 and
440 symbolsRightOfAssignment.indexOf(theSymbol) == -1 and
441 symbolsRightOfAssignment.indexOf("'"+theSymbol) == -1 and
442 !skipRootVariableToBeSolved
443 if DEBUG then console.log("... adding symbol: " + theSymbol + " to the set of the symbols right of assignment")
444 prefixVar = ""
445 for i in [1...functionInvokationsScanningStack.length]
446 if functionInvokationsScanningStack[i] != ""
447 prefixVar += functionInvokationsScanningStack[i] + "_" + i + "_"
448
449 theSymbol = prefixVar + theSymbol
450 symbolsRightOfAssignment.push theSymbol
451
452addSymbolLeftOfAssignment = (theSymbol) ->
453 if predefinedSymbolsInGlobalScope_doNotTrackInDependencies.indexOf(theSymbol) == -1 and
454 symbolsLeftOfAssignment.indexOf(theSymbol) == -1 and
455 symbolsLeftOfAssignment.indexOf("'"+theSymbol) == -1 and
456 !skipRootVariableToBeSolved
457 if DEBUG then console.log("... adding symbol: " + theSymbol + " to the set of the symbols left of assignment")
458 prefixVar = ""
459 for i in [1...functionInvokationsScanningStack.length]
460 if functionInvokationsScanningStack[i] != ""
461 prefixVar += functionInvokationsScanningStack[i] + "_" + i + "_"
462
463 theSymbol = prefixVar + theSymbol
464 symbolsLeftOfAssignment.push theSymbol
465
466scan_symbol = ->
467 if (token != T_SYMBOL)
468 scan_error("symbol expected")
469 if (meta_mode && token_buf.length == 1)
470 switch (token_buf[0])
471 when 'a'
472 push(symbol(METAA))
473 when 'b'
474 push(symbol(METAB))
475 when 'x'
476 push(symbol(METAX))
477 else
478 push(usr_symbol(token_buf))
479 else
480 push(usr_symbol(token_buf))
481 #console.log "found symbol: " + token_buf
482
483 if scanningParameters.length == 0
484 if DEBUG then console.log "out of scanning parameters, processing " + token_buf
485 lastFoundSymbol = token_buf
486 if isSymbolLeftOfAssignment
487 addSymbolLeftOfAssignment token_buf
488 else
489 if DEBUG then console.log "still scanning parameters, skipping " + token_buf
490 if isSymbolLeftOfAssignment
491 addSymbolRightOfAssignment "'" + token_buf
492
493 if DEBUG then console.log("found symbol: " + token_buf + " left of assignment: " + isSymbolLeftOfAssignment)
494
495 # if we were looking at the right part of an assignment while we
496 # found the symbol, then add it to the "symbolsRightOfAssignment"
497 # set (we check for duplications)
498 if !isSymbolLeftOfAssignment
499 addSymbolRightOfAssignment token_buf
500 get_next_token()
501
502scan_string = ->
503 new_string(token_buf)
504 get_next_token()
505
506scan_function_call_with_function_name = ->
507 if DEBUG then console.log "-- scan_function_call_with_function_name start"
508 n = 1 # the parameter number as we scan parameters
509 p = new U()
510 p = usr_symbol(token_buf)
511
512 push(p)
513 get_next_token() # function name
514 functionName = token_buf
515 if functionName == "roots" or functionName == "defint" or functionName == "sum" or functionName == "product" or functionName == "for"
516 functionInvokationsScanningStack.push token_buf
517 lastFoundSymbol = token_buf
518 if !isSymbolLeftOfAssignment
519 addSymbolRightOfAssignment token_buf
520
521 get_next_token() # 1st parameter
522 scanningParameters.push true
523 if (token != ')')
524 scan_stmt()
525 n++
526 while (token == ',')
527 get_next_token()
528 # roots' disappearing variable, if there, is the second one
529 if n == 2 and functionInvokationsScanningStack[functionInvokationsScanningStack.length - 1].indexOf("roots") != -1
530 symbolsRightOfAssignment = symbolsRightOfAssignment.filter (x) -> !(new RegExp("roots_" + (functionInvokationsScanningStack.length - 1) + "_" + token_buf)).test(x)
531 skipRootVariableToBeSolved = true
532 # sums' disappearing variable, is alsways the second one
533 if n == 2 and functionInvokationsScanningStack[functionInvokationsScanningStack.length - 1].indexOf("sum") != -1
534 symbolsRightOfAssignment = symbolsRightOfAssignment.filter (x) -> !(new RegExp("sum_" + (functionInvokationsScanningStack.length - 1) + "_" + token_buf)).test(x)
535 skipRootVariableToBeSolved = true
536 # product's disappearing variable, is alsways the second one
537 if n == 2 and functionInvokationsScanningStack[functionInvokationsScanningStack.length - 1].indexOf("product") != -1
538 symbolsRightOfAssignment = symbolsRightOfAssignment.filter (x) -> !(new RegExp("product_" + (functionInvokationsScanningStack.length - 1) + "_" + token_buf)).test(x)
539 skipRootVariableToBeSolved = true
540 # for's disappearing variable, is alsways the second one
541 if n == 2 and functionInvokationsScanningStack[functionInvokationsScanningStack.length - 1].indexOf("for") != -1
542 symbolsRightOfAssignment = symbolsRightOfAssignment.filter (x) -> !(new RegExp("for_" + (functionInvokationsScanningStack.length - 1) + "_" + token_buf)).test(x)
543 skipRootVariableToBeSolved = true
544 # defint's disappearing variables can be in positions 2,5,8...
545 if functionInvokationsScanningStack[functionInvokationsScanningStack.length - 1].indexOf("defint") != -1 and
546 (n == 2 or (n>2 and ((n-2) % 3 == 0)))
547 symbolsRightOfAssignment = symbolsRightOfAssignment.filter (x) -> !(new RegExp("defint_" + (functionInvokationsScanningStack.length - 1) + "_" + token_buf)).test(x)
548 skipRootVariableToBeSolved = true
549
550 scan_stmt()
551 skipRootVariableToBeSolved = false
552 n++
553
554 # todo refactor this, there are two copies
555 # this catches the case where the "roots" variable is not specified
556 if n == 2 and functionInvokationsScanningStack[functionInvokationsScanningStack.length - 1].indexOf("roots") != -1
557 symbolsRightOfAssignment = symbolsRightOfAssignment.filter (x) -> !(new RegExp("roots_" + (functionInvokationsScanningStack.length - 1) + "_" + "x")).test(x)
558
559 scanningParameters.pop()
560
561 for i in [0..symbolsRightOfAssignment.length]
562 if symbolsRightOfAssignment[i]?
563 if functionName == "roots"
564 symbolsRightOfAssignment[i] = symbolsRightOfAssignment[i].replace(new RegExp("roots_" + (functionInvokationsScanningStack.length - 1) + "_"),"")
565 if functionName == "defint"
566 symbolsRightOfAssignment[i] = symbolsRightOfAssignment[i].replace(new RegExp("defint_" + (functionInvokationsScanningStack.length - 1) + "_"),"")
567 if functionName == "sum"
568 symbolsRightOfAssignment[i] = symbolsRightOfAssignment[i].replace(new RegExp("sum_" + (functionInvokationsScanningStack.length - 1) + "_"),"")
569 if functionName == "product"
570 symbolsRightOfAssignment[i] = symbolsRightOfAssignment[i].replace(new RegExp("product_" + (functionInvokationsScanningStack.length - 1) + "_"),"")
571 if functionName == "for"
572 symbolsRightOfAssignment[i] = symbolsRightOfAssignment[i].replace(new RegExp("for_" + (functionInvokationsScanningStack.length - 1) + "_"),"")
573
574 if (token != ')')
575 scan_error(") expected")
576
577 get_next_token()
578 list(n)
579 if functionName == "roots" or functionName == "defint" or functionName == "sum" or functionName == "product" or functionName == "for"
580 functionInvokationsScanningStack.pop()
581 if functionName == symbol(PATTERN).printname
582 patternHasBeenFound = true
583
584 if DEBUG then console.log "-- scan_function_call_with_function_name end"
585
586scan_function_call_without_function_name = ->
587 if DEBUG then console.log "-- scan_function_call_without_function_name start"
588
589 # the function will have to be looked up
590 # at runtime
591 push_symbol(EVAL)
592 swap()
593 list(2)
594
595 n = 1 # the parameter number as we scan parameters
596 get_next_token() # left paren
597 scanningParameters.push true
598 if (token != ')')
599 scan_stmt()
600 n++
601 while (token == ',')
602 get_next_token()
603 scan_stmt()
604 n++
605
606 scanningParameters.pop()
607
608
609 if (token != ')')
610 scan_error(") expected")
611
612 get_next_token()
613 list(n)
614
615 if DEBUG then console.log "-- scan_function_call_without_function_name end: " + stack[tos-1]
616
617# scan subexpression
618
619scan_subexpr = ->
620 n = 0
621 if (token != '(')
622 scan_error("( expected")
623 get_next_token()
624 scan_stmt()
625 if (token != ')')
626 scan_error(") expected")
627 get_next_token()
628
629scan_tensor = ->
630 n = 0
631 if (token != '[')
632 scan_error("[ expected")
633
634 get_next_token()
635
636 #console.log "scanning the next statement"
637 scan_stmt()
638
639 n = 1
640 while (token == ',')
641 get_next_token()
642 scan_stmt()
643 n++
644
645 #console.log "building tensor with elements number: " + n
646 build_tensor(n)
647
648 if (token != ']')
649 scan_error("] expected")
650 get_next_token()
651
652scan_error = (errmsg) ->
653 errorMessage = ""
654
655 # try not to put question mark on orphan line
656
657 while (input_str != scan_str)
658 if ((scanned[input_str] == '\n' || scanned[input_str] == '\r') && input_str + 1 == scan_str)
659 break
660 errorMessage += scanned[input_str++]
661
662 errorMessage += " ? "
663
664 while (scanned[input_str] && (scanned[input_str] != '\n' && scanned[input_str] != '\r'))
665 errorMessage += scanned[input_str++]
666
667 errorMessage += '\n'
668
669 stop(errmsg)
670
671# There are n expressions on the stack, possibly tensors.
672#
673# This function assembles the stack expressions into a single tensor.
674#
675# For example, at the top level of the expression ((a,b),(c,d)), the vectors
676# (a,b) and (c,d) would be on the stack.
677
678# takes an integer
679build_tensor = (n) ->
680 # int i, j, k, ndim, nelem
681
682 i = 0
683
684 save()
685
686 p2 = alloc_tensor(n)
687 p2.tensor.ndim = 1
688 p2.tensor.dim[0] = n
689 for i in [0...n]
690 p2.tensor.elem[i] = stack[tos-n+i]
691
692 check_tensor_dimensions p2
693
694 moveTos tos - n
695
696 push(p2)
697
698 restore()
699
700get_next_token = ->
701 newline_flag = 0
702 while (1)
703 get_token()
704 if (token != T_NEWLINE)
705 break
706 newline_flag = 1
707 if DEBUG then console.log "get_next_token token: " + token
708 #if token == ')'
709 # debugger
710
711get_token = ->
712 # skip spaces
713 while (isspace(scanned[scan_str]))
714 if (scanned[scan_str] == '\n' || scanned[scan_str] == '\r')
715 token = T_NEWLINE
716 scan_str++
717 return
718 scan_str++
719
720 token_str = scan_str
721
722 # end of string?
723
724 if (scan_str == scanned.length)
725 token = ""
726 return
727
728 # number?
729
730 if (isdigit(scanned[scan_str]) || scanned[scan_str] == '.')
731 while (isdigit(scanned[scan_str]))
732 scan_str++
733 if (scanned[scan_str] == '.')
734 scan_str++
735 while (isdigit(scanned[scan_str]))
736 scan_str++
737 if (scanned[scan_str] == 'e' && (scanned[scan_str+1] == '+' || scanned[scan_str+1] == '-' || isdigit(scanned[scan_str+1])))
738 scan_str += 2
739 while (isdigit(scanned[scan_str]))
740 scan_str++
741 token = T_DOUBLE
742 else
743 token = T_INTEGER
744 update_token_buf(token_str, scan_str)
745 return
746
747 # symbol?
748
749 if (isalpha(scanned[scan_str]))
750 while (isalnumorunderscore(scanned[scan_str]))
751 scan_str++
752 if (scanned[scan_str] == '(')
753 token = T_FUNCTION
754 else
755 token = T_SYMBOL
756 update_token_buf(token_str, scan_str)
757 return
758
759 # string ?
760
761 if (scanned[scan_str] == '"')
762 scan_str++
763 while (scanned[scan_str] != '"')
764 #if (scan_str == scanned.length || scanned[scan_str] == '\n' || scanned[scan_str] == '\r')
765 if (scan_str == scanned.length - 1)
766 scan_str++
767 scan_error("runaway string")
768 scan_str--
769 scan_str++
770 scan_str++
771 token = T_STRING
772 update_token_buf(token_str + 1, scan_str - 1)
773 return
774
775 # comment?
776
777 if (scanned[scan_str] == '#' || scanned[scan_str] == '-' && scanned[scan_str+1] == '-')
778 while (scanned[scan_str] && scanned[scan_str] != '\n' && scanned[scan_str] != '\r')
779 scan_str++
780 if (scanned[scan_str])
781 scan_str++
782 token = T_NEWLINE
783 return
784
785 # quote-assignment
786 if (scanned[scan_str] == ':' && scanned[scan_str+1] == '=')
787 scan_str += 2
788 token = T_QUOTASSIGN
789 return
790
791 # relational operator?
792 if (scanned[scan_str] == '=' && scanned[scan_str+1] == '=')
793 scan_str += 2
794 token = T_EQ
795 return
796
797 # != operator. It's a little odd because
798 # "!" is not a "not", which would make things consistent.
799 # (it's used for factorial).
800 # An alternative would be to use "<>" but it's not used
801 # a lot in other languages...
802 if (scanned[scan_str] == '!' && scanned[scan_str+1] == '=')
803 scan_str += 2
804 token = T_NEQ
805 return
806
807 if (scanned[scan_str] == '<' && scanned[scan_str+1] == '=')
808 scan_str += 2
809 token = T_LTEQ
810 return
811
812 if (scanned[scan_str] == '>' && scanned[scan_str+1] == '=')
813 scan_str += 2
814 token = T_GTEQ
815 return
816
817 # single char token
818
819 token = scanned[scan_str++]
820
821# both strings
822update_token_buf = (a,b) ->
823
824 token_buf = scanned.substring(a,b)
825
826
827$.scan = scan