Project

General

Profile

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

haketilo / compute_scripts.awk @ 463e6830

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 wrap_file(filename) {
109
    print "\"use strict\";\n\n({fun: (function() {\n"
110
    print_imports_code(filename)
111
    printf "\n\n"
112

    
113
    print_file(filename)
114

    
115
    printf "\n\n"
116
    print_exports_code(filename)
117
    print "\n})}).fun();"
118
}
119

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

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

    
129
    processed[filename] = "on_stack"
130

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

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

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

    
150
    return 0
151
}
152

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

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

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

    
167
BEGIN {
168
    operation = ARGV[1]
169

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

    
173
    root_filename = ARGV[2]
174

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

    
178
    mock_exports_init()
179

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

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