UNPKG

5.23 kBtext/coffeescriptView Raw
1{concat, concatMap, difference, foldl, map, nub} = require './functional-helpers'
2CS = 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
14cleanMarkers = (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 # figure out which lines are needed for context
33 currentLineOffset = line - 1
34 startLine = currentLineOffset - numLinesOfContext
35 if startLine < 0 then startLine = 0
36 # get the context lines
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 # set the column number to the position of the error in the cleaned string
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# these are the identifiers that need to be declared when the given value is
52# being used as the target of an assignment
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# TODO: name change; this tests when a node is *being used as a value*
69usedAsExpression_ = (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# environment enrichments that occur when this node is evaluated
91# Note: these are enrichments of the *surrounding* environment; while function
92# parameters do enrich *an* environment, that environment is newly created
93envEnrichments_ = (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 []