-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhexdirectives.lua
More file actions
142 lines (120 loc) · 4.82 KB
/
hexdirectives.lua
File metadata and controls
142 lines (120 loc) · 4.82 KB
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
require('util')
require('fileutil')
require('hexparsing')
HexDirectives = {}
local function directive_info_directive(argument, all_nodes, nodes_in_scope, directive_index, processing_environment)
print('Argument: "'..argument..'"')
print('All nodes:')
Util.print_table(all_nodes)
print('Nodes in scope:')
Util.print_table(nodes_in_scope)
print('Directive index: '..directive_index)
print('Processing Environment:')
Util.print_table(processing_environment)
return false
end
local function msg_directive(argument, all_nodes, nodes_in_scope, directive_index, processing_environment)
print(argument)
return false
end
local function alias_directive(argument, all_nodes, nodes_in_scope, directive_index, processing_environment)
local _, _, alias_name, pattern_name = argument:find("^([%w%s%p_]*)=([%w%s%p%(%)_]*)$")
if not alias_name or not pattern_name then
error('Invalid alias declaration "'..argument..'"')
end
local alias_name_trimmed = Util.trim(alias_name)
local pattern_name_trimmed = Util.trim(pattern_name)
if alias_name_trimmed == '' or pattern_name_trimmed == '' then
error('#alias requires something on both sides of the equal sign')
end
if not processing_environment.alias_table then
processing_environment.alias_table = {}
end
processing_environment.alias_table[alias_name_trimmed] = pattern_name_trimmed
return false
end
local function include_code(nodes_in_scope, index, text)
local tokens = HexParsing.tokenize(text)
local ast = HexParsing.tokens_to_ast(tokens)
-- First we remove all nodes after the #include directive, and store them to add back later
-- nodes_after_include will be in reverse order
local nodes_after_include = {}
for _=index+1,#nodes_in_scope do
table.insert(nodes_after_include, table.remove(nodes_in_scope))
end
-- Then we add the new nodes to the end of the node list
for _,node in ipairs(ast) do
table.insert(nodes_in_scope, node)
end
-- Now we add back the nodes we removed earlier
for i=#nodes_after_include,1,-1 do
table.insert(nodes_in_scope, nodes_after_include[i])
end
end
local function include_directive(argument, all_nodes, nodes_in_scope, directive_index, processing_environment)
if argument == '' then
error("#include requires a file name")
end
if not processing_environment.current_file_path then
error('#include is only supported when compiling from a file')
end
local text = FileUtil.read_local_file(argument, processing_environment.current_file_path)
include_code(nodes_in_scope, directive_index, text)
return true
end
local function webinclude_directive(argument, all_nodes, nodes_in_scope, directive_index, processing_environment)
if argument == '' then
error("#webinclude requires a url")
end
local url = argument:match('^"(.*)"$')
if not url then
error("URL is required to be in quotes")
end
local text = FileUtil.read_web_file(url)
include_code(nodes_in_scope, directive_index, text)
return true
end
HexDirectives.directive_table = {
["directive_info"] = directive_info_directive,
["msg"] = msg_directive,
["alias"] = alias_directive,
["include"] = include_directive,
["webinclude"] = webinclude_directive
}
-- This function returns true if one of the directives modified the node tree in a suck a way that
-- that it needs to restart from the start of the file. This could happen if extra directives are
-- inserted near the front of the file.
local function run_directives_aux(all_nodes, nodes_in_scope, processing_environment)
for i,node in ipairs(nodes_in_scope) do
if node.token_type == 'directive' then
local directive = HexDirectives.directive_table[node.directive_name]
if not directive then
error('Unknown directive "#'..node.directive_name..'"')
end
node.token_type = 'noop'
local requires_reprocess =
directive(node.argument, all_nodes, nodes_in_scope, i, processing_environment)
if requires_reprocess then
return true
end
elseif node.token_type == 'list' then
local requires_reprocess =
run_directives_aux(all_nodes, node.elements, processing_environment)
if requires_reprocess then
return true
end
end
end
end
function HexDirectives.run_directives(nodes, processing_environment)
local max_tries = 64
local i = 1
local requires_reprocess = true
while requires_reprocess and i <= max_tries do
requires_reprocess = run_directives_aux(nodes, nodes, processing_environment)
i = i + 1
end
if requires_reprocess then
error("Max number of file reprocesses reached")
end
end