-
Notifications
You must be signed in to change notification settings - Fork 237
/
nubake
executable file
·183 lines (166 loc) · 7.23 KB
/
nubake
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
#!/usr/bin/env nush
#
# @file nubake
# Bake Nu scripts into Objective-C.
# When run with the "-s" option, standalone programs are created. Compile them with:
# gcc myprogram.m -o myprogram -framework Foundation -framework Nu
# Compiled programs require Nu.framework in /Library/Frameworks or another standard path.
#
# @copyright Copyright (c) 2007 Tim Burks, Radtastical Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
(class NSData
(- byteArray is
(set result "(const unsigned char[]){")
((self length) times:
(do (i) (result appendString:(+ "" (self byteAtIndex:i) ","))))
(result appendString:"0}")
result))
;; @abstract A Nu code "baker".
;; @discussion This class is used by nubake, the standalone Nu code "baker", to automatically convert Nu code into equivalent Objective-C functions.
(class NuBake is NSObject
;; Convert a Nu expression into an equivalent C expression.
;; Used internally.
;; Upon reading it, you might ask, "is this really all it takes?" It is.
(+ (id) expandNuExpression:(id) node is
(set result "")
(cond ((eq node nil)
(result appendString:"_nunull()"))
((node isKindOfClass:NuCell)
(result appendString:(+ "_nucell("
(self expandNuExpression:(node car)) ",\n"
(self expandNuExpression:(node cdr)) ")")))
((node isKindOfClass:NuSymbol)
(set data ((node stringValue) dataUsingEncoding:NSUTF8StringEncoding))
(result appendString:"_nusymbol_with_length(#{(data byteArray)}, #{(data length)})"))
((node isKindOfClass:NSString)
(set data (node dataUsingEncoding:NSUTF8StringEncoding))
(result appendString:"_nustring_with_length(#{(data byteArray)}, #{(data length)})"))
((node isKindOfClass:NSNumber)
(result appendString:"_nunumberd(#{node})"))
((node isKindOfClass:NuRegex)
(set data ((node pattern) dataUsingEncoding:NSUTF8StringEncoding))
(result appendString:"_nuregex_with_length(#{(data byteArray)}, #{(data length)}, #{(node options)})"))
(else (result appendString:"[ERROR]")))
result)
;; Generate an Objective-C source file from parsed Nu source code.
;; The file will a function named 'functionName' that when called,
;; will construct a code tree that is identical to the specified program.
;; If 'standalone' is true, a 'main()' function will be included to allow
;; the file to be compiled, linked, and run standalone.
(+ (id) bakeNuCode:(id)program intoFunction:(id)functionName standalone:(int)standalone is
(set result <<-END
#import <Foundation/Foundation.h>
#import <Nu/Nu.h>
id #{functionName}() {
return END)
(result appendString:(self expandNuExpression:program))
(result appendString:<<-END
;
}
END)
(if (standalone)
(result appendString:<<-END
int main(int argc, char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id nu = [Nu parser];
[nu eval:#{functionName}()];
[pool release];
return 0;
}
END))
result)
;; This bakes Nu code into a class method that expands and evaluates it in the main parser context.
;; The purpose is to have methods like (MyClass macros) that can be called from Nu to install
;; macros and other helpers that are written in Nu and baked into Objective-C.
(+ (id) bakeNuCode:(id)program intoMethod:(id) methodName ofCategory:(id) categoryName ofClass:(id) className is
(set result <<-END
//
// THIS FILE WAS AUTOMATICALLY GENERATED
//
// Regenerate it with nubake:
// nubake <sourcefile> --method #{methodName} --category #{categoryName} --class #{className}
//
#import <Foundation/Foundation.h>
#ifdef TARGET_OS_IPHONE
#import "Nu.h"
#else
#import <Nu/Nu.h>
#endif
#import "#{className}.h"
@implementation #{className} (#{categoryName})
+ (id) #{methodName} {
NuCell *code = END)
(result appendString:(self expandNuExpression:program))
(result appendString:<<-END
;
return [[Nu sharedParser] eval:code];
}
@end
END)
result))
;;;;;;;;;;;;;;;;;;;;;;;;;
;; main program
;;;;;;;;;;;;;;;;;;;;;;;;;
(set argv ((NSProcessInfo processInfo) arguments))
(set argi 0)
;; if we're running as a nush script, skip the nush path
(if (/(.*)nush$/ findInString:(argv 0))
(set argi (+ argi 1)))
;; skip the program name
(set argi (+ argi 1))
;; the options we need to set
(set sourceFileName nil)
(set functionName nil)
(set outputFileName nil)
(set methodName nil)
(set categoryName nil)
(set className nil)
(set standalone nil)
;; process the remaining arguments
(while (< argi (argv count))
(case (argv argi)
("-n" (set argi (+ argi 1)) (set functionName (argv argi)))
("-o" (set argi (+ argi 1)) (set outputFileName (argv argi)))
("-s" (set standalone t))
("--output" (set argi (+ argi 1)) (set outputFileName (argv argi)))
("--method" (set argi (+ argi 1)) (set methodName (argv argi)))
("--category" (set argi (+ argi 1)) (set categoryName (argv argi)))
("--class" (set argi (+ argi 1)) (set className (argv argi)))
(else (set sourceFileName (argv argi))))
(set argi (+ argi 1)))
(if sourceFileName
(then
(unless functionName
(set functionName ((sourceFileName stringByDeletingPathExtension) lastPathComponent)))
(unless outputFileName
(set outputFileName (+ (sourceFileName stringByDeletingPathExtension) ".m")))
(try
(set code (parse (NSString stringWithContentsOfFile:sourceFileName
encoding:NSUTF8StringEncoding error:nil)))
(if (and methodName categoryName className)
(then ((NuBake bakeNuCode:code
intoMethod:methodName
ofCategory:categoryName
ofClass:className)
writeToFile:outputFileName atomically:NO))
(else ((NuBake bakeNuCode:code
intoFunction:functionName
standalone:standalone)
writeToFile:outputFileName atomically:NO)))
(catch (exception)
(puts "error: #{(exception reason)}")
(set exit (NuBridgedFunction functionWithName:"exit" signature:"vi"))
(exit -1))))
(else
(puts "usage: nubake <sourcefile> [-n <functionname>] [-o <outputfilename>] [-s] or [--method <methodname> --class <classname> --category <categoryname>]")))