-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathsnow.snow
169 lines (149 loc) · 5.56 KB
/
snow.snow
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
###
Copyright 2013 Robert Kunze
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.
###
include_once dirname(!__FILE__) + "/snowcompiler.php"
outputFile = null
interactive = true
HELPERS = true
DEBUG = false
compileOnly = false
watch = false
LASTFAIL = 999999999999999
# this function waites for changes in the failed of the given directory
# if a change occurs, the callback function is called with the file that
# changes as the argument.
fn watchChanges(dir, callback)
dp = opendir dir
if not dp
throw new Exception("Unable to open directory {dir}.")
# read all the files and directory names
while (file = readdir(dp)) isnt false
path = "{dir}/{file}"
# check change time of tge snow file
oldtime = filemtime path
newfile = path->replace(/\.snow$/, '.php')
# if the current file is a snow file and it is newer than the compiled php file
if /\.snow$/->preg_match(file) isnt false and (not file_exists(newfile) or filemtime(path) > filemtime(newfile) or oldtime > LASTFAIL)
try
# call the callback function with the changed snow file
callback->call_user_func(dir + '/' + file)
LASTFAIL = 999999999999999
catch e
# if an exception occured, show the error message
echo "\n" + e.getMessage()
echo " FAILED"
# put the current time into the php file (so we will not try to
# compile it again until the .snow file changed)
file_put_contents newfile, time()
LASTFAIL = time()
else if is_dir(path) is true and file[0] isnt '.'
# if the current file is a directory and not a hidden one
# recursively call youself
watchChanges(dir + '/' + file, callback)
closedir dp
# this function compiles the given file and writes it to the hard disk
fn compile(file)
# inform the user that we are compiling the file
echo "\nCompiling {file}..."
# do the actual compilation
snow = new SnowCompiler(file->file_get_contents(), true, DEBUG)
result = snow.compile false, HELPERS
# write the result out into the php file
file->replace(/\.snow$/, '.php')->file_put_contents "<?php\n{result};\n?>"
# inform the user that we are done.
echo " OK"
# if the user provided some more arguments
if count(argv) > 1
# parse them
result = getopt "o:chwfd", ["outfile:", "compile", "help", "watch", "functions", "debug"]
args = argv->array_slice(result->count() + 1)
if args[0]?? and args[0]->file_exists()
code = file_get_contents args[0]
interactive = false
# if the user provided the parameter to name his output file
if result['o']?? or result['outfile']??
# we store the value
outputFile = result['o']
if result['d']? or result['debug']?
DEBUG = true
if result['f']? or result['functions']?
HELPERS = false
# if the user chose to have the code only compiled & not executed
if result['c']? or result['compile']?
compileOnly = true
# if the user wants to watch current execution directory and
# auto-compile all snow files in it as soon as they change
if result['w']? or result['watch']?
watch = true
# if the user wants to review the help
if result['h']? or result['help']?
ver = SnowCompiler..version
help = """
Snow Script Compiler Version {ver}
Syntax:
{argv[0]} [-o <output file>] [-chwfd] [<input file>]
-o <output file> - write the compiled result into the given file. If this parameter is missing, the compiled result will be written to stdout.
-c - the input should only be compiled - not executed
-h - shows this help
-d - enable the debugger() function
-f - do not include helper functions into the compiled output
-w - watch mode: compile any changed snow file in given directory tree
<input file> - the file that should be used as input. if this parameter is omitted, an interactive console will let you enter commands.
"""
die help
# in case the user activated the watch mode
if watch
# tell him so
echo "Waiting for file changes..."
# and loop until the end of time (or the user presses CTRL+C)
while true is true
# for all changes, compile the respective file
watchChanges ".", 'compile'
sleep 1
do die
# if the options enable the interactive mode (no file given)
if interactive
# read the code from stdin
fp = fopen "php://stdin", 'r'
input = ""
while not feof fp
# read until the user sends the EOF signal (CTRL+D)
input = input % fread(fp, 4096)
# and use the input as the source code
code = input
# compile the source code
snow = new SnowCompiler(code, true, DEBUG)
result = snow.compile false, HELPERS
# if the user only wanted to compile the source
if compileOnly is true
# wrap it
result = "<?php\n{result};\n?>"
# if an output file was given
if outputFile??
# write the resulting code into the output file
file_put_contents outputFile, result
else
# else print it out on the screen
echo result
else if compileOnly is false
# if the user wanted the code to be executed
lines = ";"->explode(result)
# find the last code line
for i in count(lines) - 1 downto 0
trimmed = trim lines[i]
if not empty trimmed
lines[i] = "return " + lines[i]
break
# then evaluate the resulting code
result = eval ";"->implode lines
# and print it's result
echo result