Project

General

Profile

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

haketilo / compute_scripts.awk @ 6106c789

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.killtheweb.%s;\n", import_name, import_name
96
    }
97
}
98

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

    
107
function wrap_file(filename) {
108
    print "\"use strict\";\n\n({fun: (function() {\n"
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
    print "\n})}).fun();"
117
}
118

    
119
function compute_dependencies(filename,    i, count, import_name, next_file) {
120
    if (processed[filename] == "used")
121
	return 0
122

    
123
    if (processed[filename] == "on_stack") {
124
	printf "import loop on %s\n", filename > "/dev/stderr"
125
	return 1
126
    }
127

    
128
    processed[filename] = "on_stack"
129

    
130
    count = import_counts[filename]
131
    for (i = 1; i <= count; i++) {
132
	import_name = imports[filename,i]
133
	if (!(import_name in provides)) {
134
	    printf "nothing exports %s, required by %s\n",
135
		import_name, filename > "/dev/stderr"
136
	    return 1
137
	}
138

    
139
	if (compute_dependencies(provides[import_name]) > 0) {
140
	    printf "when satisfying %s for %s\n",
141
		import_name, filename > "/dev/stderr"
142
	    return 1
143
	}
144
    }
145

    
146
    processed[filename] = "used"
147
    print filename
148

    
149
    return 0
150
}
151

    
152
function print_usage() {
153
    printf "usage:  %2 compute_scripts.awk script_dependencies|wrapped_code FILENAME[...]\n",
154
	ARGV[0] > "/dev/stderr"
155
    exit 1
156
}
157

    
158
function mock_exports_init() {
159
    provides["browser"]    = "exports_init.js"
160
    provides["is_chrome"]  = "exports_init.js"
161
    provides["is_mozilla"] = "exports_init.js"
162

    
163
    processed["exports_init.js"] = "used"
164
}
165

    
166
BEGIN {
167
    operation = ARGV[1]
168

    
169
    if (ARGC < 3)
170
	print_usage()
171

    
172
    root_filename = ARGV[2]
173

    
174
    for (i = 2; i < ARGC; i++)
175
	filenames[ARGV[i]]
176

    
177
    mock_exports_init()
178

    
179
    for (filename in filenames) {
180
	# A filename is allowed to appear multiple times in the list.
181
	# Let's only process it once.
182
	if (!(filename in processed))
183
	    read_file(filename)
184
	processed[filename] = "not_used"
185
    }
186

    
187
    if (operation == "script_dependencies") {
188
	print("exports_init.js")
189
	if (compute_dependencies(root_filename) > 0)
190
	    exit 1
191
    } else if (operation == "wrapped_code") {
192
	wrap_file(root_filename)
193
    } else {
194
	print_usage()
195
    }
196
}
(6-6/16)