forked from satyr/coco
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCokefile
185 lines (160 loc) · 5.96 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
175
176
177
178
179
180
181
182
183
184
185
{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 \bin/coco args
proc.stderr.on \data say
proc .on \exit -> process.exit it if it
slobber = (path, code) ->
spit path, code
say '* ' + path
minify = ->
{parser, uglify} = require \uglify-js
ast = parser.parse it
ast = uglify.ast_mangle ast
ast = uglify.ast_squeeze ast
uglify.gen_code ast
option \prefix 'set the installation prefix for `install`' \DIR
task \install 'install Coco into /usr/local (or --prefix)' (options) ->
base = options.prefix or \/usr/local
lib = "#base/lib/coco"
bin = "#base/bin"
nlib = \~/.node_libraries
e, stdout, stderr <- exec """
echo Installing Coco to #lib
mkdir -p #lib #bin #nlib
cp -rf lib LICENSE README.md package.json #lib
ln -sfv #lib/lib/command.js #bin/coco
ln -sfv #lib/lib/coke.js #bin/coke
ln -sfnv #lib/lib #nlib/coco
"""replace /\n/g \&&
say stdout.trim! if stdout
say if e then stderr.trim! else tint \done
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' ->
exec 'bin/coke build && bin/coke build && bin/coke test'
, (err, stdout, stderr) ->
say stdout.trim! if stdout
say stderr.trim! if stderr
throw err if err
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 2011, Jeremy Ashkenas + Satoshi Murakami
// Released under the MIT License
http://satyr.github.com/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
function runTests global.Coco
startTime = Date.now!
passedTests = failedTests = 0
for name, func in require \assert then let
global[name] = -> func ...; ++passedTests
global <<<
eq: strictEqual
throws: (msg, fun) ->
try do fun catch return eq e?message, msg
ok false "should throw: #msg"
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
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