Project

General

Profile

Download (5.43 KB) Statistics
| Branch: | Tag: | Revision:

haketilo / compute_scripts.awk @ 3a90084e

1
# SPDX-License-Identifier: CC0-1.0
2
#
3
# Process javascript files and resolve dependencies between them
4
#
5
# This file is part of Haketilo
6
#
7
# Copyright (C) 2021, Wojtek Kosior
8
#
9
# This program is free software: you can redistribute it and/or modify
10
# it under the terms of the CC0 1.0 Universal License as published by
11
# the Creative Commons Corporation.
12
#
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
# CC0 1.0 Universal License for more details.
17

    
18
function read_file(filename,
19
		   imports_state, exports_state, line, record, result) {
20
    imports_state = "not_started"
21
    exports_state = "not_started"
22

    
23
    do {
24
	result = (getline line < filename)
25
	if (result < 0) {
26
	    printf "error reading %s", filename
27
	    exit 1
28
	}
29

    
30
	if (imports_state == "started" &&
31
	    line ~ /^([[:space:]]*\*[[:space:]]+)?IMPORT[[:space:]]+[_a-zA-Z][_a-zA-Z0-9]*[[:space:]]*$/) {
32
	    record = line
33

    
34
	    sub(/^([[:space:]]*\*[[:space:]]+)?IMPORT[[:space:]]+/, "", record)
35
	    sub(/([[:space:]]+$)/,                                  "", record)
36

    
37
	    imports[filename,++import_counts[filename]] = record
38
	}
39
	if (imports_state == "started" &&
40
	    line ~ /^([[:space:]]*\*[[:space:]]+)?IMPORTS_END[[:space:]]*$/)
41
	    imports_state = "finished"
42
	if (imports_state == "not_started" &&
43
	    line ~ /^([[:space:]]*\*[[:space:]]+)?IMPORTS_START[[:space:]]*$/)
44
	    imports_state = "started"
45

    
46
	if (exports_state == "started" &&
47
	    line ~ /^([[:space:]]*\*[[:space:]]+)?EXPORT[[:space:]]+[_a-zA-Z][_a-zA-Z0-9]*[[:space:]]*$/) {
48
	    record = line
49

    
50
	    sub(/^([[:space:]]*\*[[:space:]]+)?EXPORT[[:space:]]+/, "", record)
51
	    sub(/([[:space:]]+$)/,                                  "", record)
52

    
53
	    if (record in exports) {
54
		printf "ERROR: '%s' exported by both %s and %s\n",
55
		    exports[record], filename > "/dev/stderr"
56
	    }
57

    
58
	    provides[record] = filename
59
	    exports[filename,++export_counts[filename]] = record
60
	}
61
	if (exports_state == "started" &&
62
	    line ~ /^([[:space:]]*\*[[:space:]]+)?EXPORTS_END[[:space:]]*$/)
63
	    exports_state = "finished"
64
	if (exports_state == "not_started" &&
65
	    line ~ /^([[:space:]]*\*[[:space:]]+)?EXPORTS_START[[:space:]]*$/)
66
	    exports_state = "started"
67
    } while (result > 0)
68

    
69
    if (imports_state == "started") {
70
	printf "ERROR: Unclosed IMPORTS list in '%s'\n", filename	\
71
	    > "/dev/stderr"
72
	exit 1
73
    }
74

    
75
    if (exports_state == "started") {
76
	printf "ERROR: Unclosed EXPORTS list in '%s'\n", filename	\
77
	    > "/dev/stderr"
78
	exit 1
79
    }
80

    
81
    close(filename)
82
}
83

    
84
function print_file(filename,    line) {
85
    while ((getline line < filename) > 0)
86
	print(line)
87

    
88
    close(filename)
89
}
90

    
91
function print_imports_code(filename,    i, count, import_name) {
92
    count = import_counts[filename]
93
    for (i = 1; i <= count; i++) {
94
	import_name = imports[filename,i]
95
	printf "const %s = window.haketilo_exports.%s;\n",
96
	    import_name, import_name
97
    }
98
}
99

    
100
function print_exports_code(filename,    i, count, export_name) {
101
    count = export_counts[filename]
102
    for (i = 1; i <= count; i++) {
103
	export_name = exports[filename,i]
104
	printf "window.haketilo_exports.%s = %s;\n", export_name, export_name
105
    }
106
}
107

    
108
function partially_wrap_file(filename) {
109
    print_imports_code(filename)
110
    printf "\n\n"
111

    
112
    print_file(filename)
113

    
114
    printf "\n\n"
115
    print_exports_code(filename)
116
}
117

    
118
function wrap_file(filename) {
119
    print "\"use strict\";\n\n({fun: (function() {\n"
120

    
121
    partially_wrap_file(filename)
122

    
123
    print "\n})}).fun();"
124
}
125

    
126
function compute_dependencies(filename,    i, count, import_name, next_file) {
127
    if (processed[filename] == "used")
128
	return 0
129

    
130
    if (processed[filename] == "on_stack") {
131
	printf "import loop on %s\n", filename > "/dev/stderr"
132
	return 1
133
    }
134

    
135
    processed[filename] = "on_stack"
136

    
137
    count = import_counts[filename]
138
    for (i = 1; i <= count; i++) {
139
	import_name = imports[filename,i]
140
	if (!(import_name in provides)) {
141
	    printf "nothing exports %s, required by %s\n",
142
		import_name, filename > "/dev/stderr"
143
	    return 1
144
	}
145

    
146
	if (compute_dependencies(provides[import_name]) > 0) {
147
	    printf "when satisfying %s for %s\n",
148
		import_name, filename > "/dev/stderr"
149
	    return 1
150
	}
151
    }
152

    
153
    processed[filename] = "used"
154
    print filename
155

    
156
    return 0
157
}
158

    
159
function print_usage() {
160
    printf "usage:  %2 compute_scripts.awk script_dependencies|wrapped_code|partially_wrapped_code FILENAME[...]\n",
161
	ARGV[0] > "/dev/stderr"
162
    exit 1
163
}
164

    
165
function mock_exports_init() {
166
    provides["browser"]      = "exports_init.js"
167
    provides["is_chrome"]    = "exports_init.js"
168
    provides["is_mozilla"]   = "exports_init.js"
169
    provides["initial_data"] = "exports_init.js"
170

    
171
    processed["exports_init.js"] = "used"
172
}
173

    
174
BEGIN {
175
    operation = ARGV[1]
176

    
177
    if (ARGC < 3)
178
	print_usage()
179

    
180
    root_filename = ARGV[2]
181

    
182
    for (i = 2; i < ARGC; i++)
183
	filenames[ARGV[i]]
184

    
185
    mock_exports_init()
186

    
187
    for (filename in filenames) {
188
	# A filename is allowed to appear multiple times in the list.
189
	# Let's only process it once.
190
	if (!(filename in processed))
191
	    read_file(filename)
192
	processed[filename] = "not_used"
193
    }
194

    
195
    if (operation == "script_dependencies") {
196
	print("exports_init.js")
197
	if (compute_dependencies(root_filename) > 0)
198
	    exit 1
199
    } else if (operation == "partially_wrapped_code") {
200
	partially_wrap_file(root_filename)
201
    } else if (operation == "wrapped_code") {
202
	wrap_file(root_filename)
203
    } else {
204
	print_usage()
205
    }
206
}
(7-7/18)