-
Notifications
You must be signed in to change notification settings - Fork 48
/
Cokefile
174 lines (149 loc) · 5.6 KB
/
Cokefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
{spawn, exec} = require \child_process
# ANSI Terminal Colors.
bold = '\33[0;1m'
red = '\33[0;31m'
green = '\33[0;32m'
reset = '\33[0m'
tint = (text, color ? green) -> color + text + reset
# Run our node/coco interpreter.
run = (args) ->
proc = spawn \node [\lib/command]concat args
proc.stdout.pipe process.stdout
proc.stderr.pipe process.stderr
proc.on \exit -> process.exit it if it
shell = (command) ->
err, sout, serr <- exec command
process.stdout.write sout if sout
process.stderr.write serr if serr
console.log err if err
slobber = (path, code) ->
spit path, code
say '* ' + path
minify = ->
require \uglify-js .minify it, {+fromString} .code
task \install 'install Coco via npm' -> shell 'npm install -g .'
docs = <[ doc.co lang-co.co ]>
task \build 'build lib/ from src/' ->
ext = /\.co$/; webs = docs.concat \mode-coco.co
sources = for file of dir \src
\src/ + file if ext.test file and file not of webs
run [\-bco \lib]concat sources
task \build:full 'build twice and run tests' ->
shell 'bin/coke build && bin/coke build && bin/coke test'
task \build:parser 'build lib/parser.js from lib/grammar.js' ->
spit \lib/parser.js,
require(\./lib/grammar)generate!
.replace /^[^]+?var (?=parser = {)/ \exports.
.replace /\ncase \d+:\nbreak;/g ''
.replace /return parser;[^]+/ ''
.replace /(:[^]+?break;)(?=\ncase \d+\1)/g \:
.replace /(:return .+)\nbreak;/g \$1
task \build:doc 'build doc/' ->
<- docs.forEach
name = it.slice 0 -3; js = require(\./lib/coco)compile slurp \src/ + it
fs.writeFile "doc/#name.raw.js" js
slobber "doc/#name.js" minify js
task \build:browser 'build extras/' ->
Coco = require \./lib/coco
js = Coco.compile slurp \src/mode-coco.co
fs.writeFile \extras/mode-coco.raw.js js
slobber \extras/mode-coco.js minify js
co = ''
for name of <[ lexer ast coco ]>
code = slurp("src/#name.co")replace /\n/g '\n '
co += "let exports = require'./#name' = {}\n#code\n"
fs.writeFile \extras/coco.raw.js js = """
this.Coco = function(){
function require(path){ return require[path] }
var exports = require['./parser'] = {}; #{ slurp \lib/parser.js }
#{ Coco.compile co, {+bare} }
return require['./coco']
}()
this.window && function(){\n#{ slurp \lib/browser.js }\n}()
this.WSH && function(){\n#{ slurp \lib/wsh.js }\n}()
this.Coco
"""
slobber \extras/coco.js """
// Coco #{Coco.VERSION}
// Copyright 2012, Jeremy Ashkenas + Satoshi Murakami
// Released under the MIT License
http://satyr.github.io/coco
#{ minify js }
"""
invoke \test:browser
coreSources = -> "src/#src.co" for src of <[ coco grammar lexer ast ]>
task \bench 'quick benchmark of compilation time' ->
Coco = require \./lib/coco
co = coreSources!map(-> slurp it)join \\n
fmt = -> "#bold#{ " #it"slice -4 }#reset ms"
total = nc = 0
now = Date.now!
time = -> total += ms = -(now - now := Date.now!); fmt ms
tokens = Coco.lex co
msg = "Lex #{time!} (#{tokens.length} tokens)\n"
Coco.tokens.rewrite tokens
msg += "Rewrite #{time!} (#{tokens.length} tokens)\n"
tree = Coco.ast tokens
msg += "Parse #{time!} (%s nodes)\n"
js = tree.compileRoot {+bare}
msg += "Compile #{time!} (#{js.length} chars)\n" +
"TOTAL #{ fmt total }"
tree.traverseChildren (-> ++nc; void), true
console.log msg, nc
task \loc 'count the lines of main compiler code' ->
count = 0; line = /^[^\n\S]*[^#\s]/mg
++count while line.test code for code of coreSources!map -> slurp it
console.log count
task \test 'run test/' -> runTests require \./lib/coco
task \test:browser 'run test/ against extras/coco.js' ->
runTests (new new Function slurp \extras/coco.js)Coco
task \test:json 'test JSON {de,}serialization' ->
{ast} = require \./lib/coco
json = ast slurp \src/ast.co .stringify!
code = ast.parse json .compileRoot {+bare}
exec 'diff -u lib/ast.js -' (e, out) -> say e || out.trim! || tint \ok
.stdin.end code
task \test:event 'test compiler events' ->
run <[ -bcr ./test/cli/event.co -e ok ]>
function runTests global.Coco
startTime = Date.now!
passedTests = failedTests = 0
for let name, func in require \assert
global[name] = !->
func ...
++passedTests
global <<<
eq: strictEqual
throws: !(msg, fun) ->
try do fun catch return eq e?message, msg
ok false "should throw: #msg"
compileThrows: !(msg, lno, code) ->
throws "#msg on line #lno" !-> Coco.compile code
process.on \exit ->
time = ((Date.now! - startTime) / 1e3)toFixed 2
message = "passed #passedTests tests in #time seconds"
say if failedTests
then tint "failed #failedTests and #message" red
else tint message
dir(\test)forEach (file) ->
return unless /\.co$/i.test file
code = slurp filename = path.join \test file
try Coco.run code, {filename} catch
++failedTests
return say e unless stk = e?stack
msg = e.message or ''+ /^[^]+?(?=\n at )/exec stk
if m = /^(AssertionError:) "(.+)" (===) "(.+)"$/exec msg
m[i] = tint m[i]replace(/\\n/g \\n), bold for i of [2 4]
msg = m.slice(1)join \\n
[, row, col]? = //#filename:(\d+):(\d+)\)?$//m.exec stk
if row and col
say tint "#msg\n#{red}at #filename:#{row--}:#{col--}" red
code = Coco.compile code, {+bare}
else if /\bon line (\d+)\b/exec msg
say tint msg, red
row = that.1 - 1
col = 0
else return say stk
{(row): line} = lines = code.split \\n
lines[row] = line.slice(0 col) + tint line.slice(col), bold
say lines.slice(row-8 >? 0, row+9)join \\n