1 | {concat, concatMap, difference, foldl, map, nub} = require './functional-helpers'
|
2 | CS = require './nodes'
|
3 |
|
4 |
|
5 | @numberLines = numberLines = (input, startLine = 1) ->
|
6 | lines = input.split '\n'
|
7 | padSize = "#{lines.length + startLine - 1}".length
|
8 | numbered = for line, i in lines
|
9 | currLine = "#{i + startLine}"
|
10 | pad = ((Array padSize + 1).join '0')[currLine.length..]
|
11 | "#{pad}#{currLine} : #{lines[i]}"
|
12 | numbered.join '\n'
|
13 |
|
14 | cleanMarkers = (str) -> str.replace /[\uEFEF\uEFFE\uEFFF]/g, ''
|
15 |
|
16 | @humanReadable = humanReadable = (str) ->
|
17 | ((str.replace /\uEFEF/g, '(INDENT)').replace /\uEFFE/g, '(DEDENT)').replace /\uEFFF/g, '(TERM)'
|
18 |
|
19 | @formatParserError = (input, e) ->
|
20 | realColumn = (cleanMarkers "#{(input.split '\n')[e.line - 1]}\n"[...e.column]).length
|
21 | unless e.found?
|
22 | return "Syntax error on line #{e.line}, column #{realColumn}: unexpected end of input"
|
23 | found = JSON.stringify humanReadable e.found
|
24 | found = ((found.replace /^"|"$/g, '').replace /'/g, '\\\'').replace /\\"/g, '"'
|
25 | unicode = ((e.found.charCodeAt 0).toString 16).toUpperCase()
|
26 | unicode = "\\u#{"0000"[unicode.length..]}#{unicode}"
|
27 | message = "Syntax error on line #{e.line}, column #{realColumn}: unexpected '#{found}' (#{unicode})"
|
28 | "#{message}\n#{pointToErrorLocation input, e.line, realColumn}"
|
29 |
|
30 | @pointToErrorLocation = pointToErrorLocation = (source, line, column, numLinesOfContext = 3) ->
|
31 | lines = source.split '\n'
|
32 |
|
33 | currentLineOffset = line - 1
|
34 | startLine = currentLineOffset - numLinesOfContext
|
35 | if startLine < 0 then startLine = 0
|
36 |
|
37 | preLines = lines[startLine..currentLineOffset]
|
38 | postLines = lines[currentLineOffset + 1 .. currentLineOffset + numLinesOfContext]
|
39 | numberedLines = (numberLines (cleanMarkers [preLines..., postLines...].join '\n'), startLine + 1).split '\n'
|
40 | preLines = numberedLines[0...preLines.length]
|
41 | postLines = numberedLines[preLines.length...]
|
42 |
|
43 | column = (cleanMarkers "#{lines[currentLineOffset]}\n"[...column]).length
|
44 | padSize = ((currentLineOffset + 1 + postLines.length).toString 10).length
|
45 | [
|
46 | preLines...
|
47 | "#{(Array padSize + 1).join '^'} :~#{(Array column).join '~'}^"
|
48 | postLines...
|
49 | ].join '\n'
|
50 |
|
51 |
|
52 |
|
53 | @beingDeclared = beingDeclared = (assignment) -> switch
|
54 | when not assignment? then []
|
55 | when assignment.instanceof CS.Identifiers then [assignment.data]
|
56 | when assignment.instanceof CS.Rest then beingDeclared assignment.expression
|
57 | when assignment.instanceof CS.MemberAccessOps then []
|
58 | when assignment.instanceof CS.DefaultParam then beingDeclared assignment.param
|
59 | when assignment.instanceof CS.ArrayInitialiser then concatMap assignment.members, beingDeclared
|
60 | when assignment.instanceof CS.ObjectInitialiser then concatMap assignment.vals(), beingDeclared
|
61 | else throw new Error "beingDeclared: Non-exhaustive patterns in case: #{assignment.className}"
|
62 |
|
63 | @declarationsFor = (node, inScope) ->
|
64 | vars = envEnrichments node, inScope
|
65 | foldl (new CS.Undefined).g(), vars, (expr, v) ->
|
66 | (new CS.AssignOp (new CS.Identifier v).g(), expr).g()
|
67 |
|
68 |
|
69 | usedAsExpression_ = (ancestors) ->
|
70 | parent = ancestors[0]
|
71 | grandparent = ancestors[1]
|
72 | switch
|
73 | when !parent? then yes
|
74 | when parent.instanceof CS.Program, CS.Class then no
|
75 | when parent.instanceof CS.SeqOp
|
76 | this is parent.right and
|
77 | usedAsExpression parent, ancestors[1..]
|
78 | when (parent.instanceof CS.Block) and
|
79 | (parent.statements.indexOf this) isnt parent.statements.length - 1
|
80 | no
|
81 | when (parent.instanceof CS.Functions) and
|
82 | parent.body is this and
|
83 | grandparent? and grandparent.instanceof CS.Constructor
|
84 | no
|
85 | else yes
|
86 |
|
87 | @usedAsExpression = usedAsExpression = (node, ancestors) ->
|
88 | usedAsExpression_.call node, ancestors
|
89 |
|
90 |
|
91 |
|
92 |
|
93 | envEnrichments_ = (inScope = []) ->
|
94 | possibilities = switch
|
95 | when @instanceof CS.AssignOp then nub beingDeclared @assignee
|
96 | when @instanceof CS.Class
|
97 | nub concat [
|
98 | beingDeclared @nameAssignee
|
99 | envEnrichments @parent
|
100 | if name? then [name] else []
|
101 | ]
|
102 | when @instanceof CS.ForIn, CS.ForOf
|
103 | nub concat [
|
104 | concatMap @childNodes, (child) =>
|
105 | if child in @listMembers
|
106 | then concatMap @[child], (m) -> envEnrichments m, inScope
|
107 | else envEnrichments @[child], inScope
|
108 | beingDeclared @keyAssignee
|
109 | beingDeclared @valAssignee
|
110 | ]
|
111 | when @instanceof CS.Functions then []
|
112 | else
|
113 | nub concatMap @childNodes, (child) =>
|
114 | if child in @listMembers
|
115 | then concatMap @[child], (m) -> envEnrichments m, inScope
|
116 | else envEnrichments @[child], inScope
|
117 | difference possibilities, inScope
|
118 |
|
119 | @envEnrichments = envEnrichments = (node, args...) ->
|
120 | if node? then envEnrichments_.apply node, args else []
|