bel 0.3.0.beta1-x64-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/INSTALL.md +19 -0
- data/INSTALL_RUBY.md +107 -0
- data/LICENSE +191 -0
- data/README.md +319 -0
- data/bel.gemspec +67 -0
- data/bin/bel2rdf +134 -0
- data/bin/bel_compare +177 -0
- data/bin/bel_parse +60 -0
- data/bin/bel_rdfschema +72 -0
- data/bin/bel_summarize +86 -0
- data/bin/bel_upgrade +175 -0
- data/bin/bel_upgrade_term +163 -0
- data/ext/mri/bel-ast.c +221 -0
- data/ext/mri/bel-ast.h +82 -0
- data/ext/mri/bel-node-stack.c +83 -0
- data/ext/mri/bel-node-stack.h +26 -0
- data/ext/mri/bel-parse-statement.c +122296 -0
- data/ext/mri/bel-parse-term.c +117670 -0
- data/ext/mri/bel-parser.c +91 -0
- data/ext/mri/bel-parser.h +13 -0
- data/ext/mri/bel-token.c +161 -0
- data/ext/mri/bel-token.h +58 -0
- data/ext/mri/bel-tokenize-term.c +391 -0
- data/ext/mri/extconf.rb +8 -0
- data/ext/mri/libbel.c +5 -0
- data/ext/mri/libbel.def +26 -0
- data/lib/bel.rb +17 -0
- data/lib/bel/completion.rb +53 -0
- data/lib/bel/completion_rule.rb +236 -0
- data/lib/bel/language.rb +1052 -0
- data/lib/bel/namespace.rb +323 -0
- data/lib/bel/quoting.rb +29 -0
- data/lib/bel/rdf.rb +314 -0
- data/lib/bel/script.rb +239632 -0
- data/lib/features.rb +21 -0
- data/lib/libbel.rb +201 -0
- data/lib/libbel.so +0 -0
- data/lib/util.rb +125 -0
- metadata +269 -0
data/bin/bel_summarize
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim: ts=2 sw=2
|
3
|
+
|
4
|
+
require 'bel'
|
5
|
+
require 'csv'
|
6
|
+
require 'optparse'
|
7
|
+
include BEL::Language
|
8
|
+
include BEL::Namespace
|
9
|
+
|
10
|
+
options = {}
|
11
|
+
OptionParser.new do |opts|
|
12
|
+
opts.banner = '''Statistic report for BEL script.
|
13
|
+
Usage: bel_summarize --bel [FILE]'''
|
14
|
+
|
15
|
+
opts.on('-b', '--bel FILE', 'BEL file to summarize. STDIN (standard in) can also be used for BEL content.') do |bel|
|
16
|
+
options[:bel] = bel
|
17
|
+
end
|
18
|
+
end.parse!
|
19
|
+
|
20
|
+
# read bel content
|
21
|
+
content =
|
22
|
+
if options[:bel]
|
23
|
+
File.open(options[:bel]).read
|
24
|
+
else
|
25
|
+
$stdin.read
|
26
|
+
end
|
27
|
+
|
28
|
+
CSV do |csv_out|
|
29
|
+
report = {
|
30
|
+
statement_group_count: 0,
|
31
|
+
empty_statement_groups: 0,
|
32
|
+
statement_count: 0,
|
33
|
+
evidence_count: 0
|
34
|
+
}
|
35
|
+
|
36
|
+
FUNCTIONS.each do |k, v|
|
37
|
+
report['fx_' + v[:long_form].to_s] = 0
|
38
|
+
end
|
39
|
+
|
40
|
+
RELATIONSHIPS.each do |r|
|
41
|
+
report['rel_' + r.to_s] = 0
|
42
|
+
end
|
43
|
+
|
44
|
+
active_group = nil
|
45
|
+
BEL::Script.parse(content) do |obj|
|
46
|
+
if obj.is_a? BEL::Language::StatementGroup
|
47
|
+
report[:statement_group_count] += 1
|
48
|
+
active_group = obj
|
49
|
+
end
|
50
|
+
if obj.is_a? BEL::Language::UnsetStatementGroup
|
51
|
+
if active_group.statements.empty?
|
52
|
+
report[:empty_statement_groups] += 1
|
53
|
+
end
|
54
|
+
end
|
55
|
+
if obj.is_a? BEL::Language::Term
|
56
|
+
report['fx_' + obj.fx[:long_form].to_s] += 1
|
57
|
+
end
|
58
|
+
if obj.is_a? BEL::Language::Statement
|
59
|
+
report[:statement_count] += 1
|
60
|
+
obj.relationship = case obj.relationship
|
61
|
+
when :"->"
|
62
|
+
:increases
|
63
|
+
when :"-|"
|
64
|
+
:decreases
|
65
|
+
when :"=>"
|
66
|
+
:directlyIncreases
|
67
|
+
when :"=|"
|
68
|
+
:directlyDecreases
|
69
|
+
when :"--"
|
70
|
+
:association
|
71
|
+
else
|
72
|
+
obj.relationship
|
73
|
+
end
|
74
|
+
|
75
|
+
if obj.relationship
|
76
|
+
report['rel_' + obj.relationship.to_s] += 1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
if obj.is_a? BEL::Language::Annotation
|
80
|
+
report[:evidence_count] += 1 if obj.name == 'Evidence'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
csv_out << report.keys
|
85
|
+
csv_out << report.values
|
86
|
+
end
|
data/bin/bel_upgrade
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# bel_upgrade: Upgrade BEL content to a new set of resources.
|
3
|
+
#
|
4
|
+
# From BEL file
|
5
|
+
# usage: bel_upgrade -b file.bel -c file.json
|
6
|
+
#
|
7
|
+
# From standard in
|
8
|
+
# usage: echo "<BEL DOCUMENT STRING>" | bel_upgrade -c file.json
|
9
|
+
|
10
|
+
require 'bel'
|
11
|
+
require 'json'
|
12
|
+
require 'optparse'
|
13
|
+
require 'set'
|
14
|
+
require 'open-uri'
|
15
|
+
|
16
|
+
# setup and parse options
|
17
|
+
options = {}
|
18
|
+
OptionParser.new do |opts|
|
19
|
+
opts.banner = "Usage: bel_upgrade [options] [.bel file]"
|
20
|
+
opts.on('-b', '--bel FILE', 'BEL file to upgrade. STDIN (standard in) can also be used for BEL content.') do |bel|
|
21
|
+
options[:bel] = bel
|
22
|
+
end
|
23
|
+
opts.on("-c", "--changelog [FILE | URI]", "Change log JSON") do |change_log|
|
24
|
+
options['change_log'] = change_log
|
25
|
+
end
|
26
|
+
end.parse!
|
27
|
+
|
28
|
+
# option guards
|
29
|
+
unless options[:bel] or not STDIN.tty?
|
30
|
+
$stderr.puts "No bel content provided. Either use --bel option or STDIN (standard in). Use -h / --help for details."
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
unless options['change_log']
|
34
|
+
$stderr.puts "Missing --changelog option. Use -h / --help for details."
|
35
|
+
exit 1
|
36
|
+
end
|
37
|
+
if not File.exists? options['change_log']
|
38
|
+
begin
|
39
|
+
open(options['change_log']) do |f|
|
40
|
+
unless f.content_type == 'application/json'
|
41
|
+
$stderr.puts "Expected application/json content type, actual: #{f.content_type}"
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
rescue OpenURI::HTTPError => e
|
46
|
+
$stderr.puts "Cannot read URI for change_log, #{options['change_log']}, status: #{e}"
|
47
|
+
exit 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
if options[:bel] and not File.exists? options[:bel]
|
51
|
+
$stderr.puts "No file for bel, #{options[:bel]}"
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
|
55
|
+
# read bel content
|
56
|
+
content =
|
57
|
+
if options[:bel]
|
58
|
+
File.open(options[:bel]).read
|
59
|
+
else
|
60
|
+
$stdin.read
|
61
|
+
end
|
62
|
+
|
63
|
+
# read change log
|
64
|
+
changelog = nil
|
65
|
+
if File.exists? options['change_log']
|
66
|
+
File.open(options['change_log']) do |f|
|
67
|
+
changelog = JSON.parse(f.read)
|
68
|
+
end
|
69
|
+
else
|
70
|
+
open(options['change_log']) do |file|
|
71
|
+
changelog = JSON.parse(file.read)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
unless changelog
|
76
|
+
$stderr.puts "Cannot retrieve change_log #{options['change_log']}"
|
77
|
+
end
|
78
|
+
|
79
|
+
class Main
|
80
|
+
|
81
|
+
EvidenceMatcher = Regexp.compile(/SET Evidence = ([0-9a-zA-Z]+)/)
|
82
|
+
LostReplaceValues = ['unresolved', 'withdrawn']
|
83
|
+
attr_reader :ttl
|
84
|
+
|
85
|
+
def initialize(content, change_log)
|
86
|
+
@change_log = change_log
|
87
|
+
@redefine_section = @change_log['redefine']
|
88
|
+
@keywords_seen = Set.new
|
89
|
+
BEL::Script.parse(content) do |obj|
|
90
|
+
# redefine namespace based on change log's `redefine` block
|
91
|
+
if obj.is_a? NamespaceDefinition
|
92
|
+
if @change_log.has_key? 'redefine'
|
93
|
+
redefine = @change_log['redefine']
|
94
|
+
if redefine.has_key? obj.prefix.to_s
|
95
|
+
entry = redefine[obj.prefix.to_s]
|
96
|
+
new_keyword = entry['new_keyword'].to_sym
|
97
|
+
new_url = entry['new_url']
|
98
|
+
obj = NamespaceDefinition.new(new_keyword, new_url)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# deduplicate namespaces for output purposes
|
103
|
+
if @keywords_seen.include? obj.prefix
|
104
|
+
next
|
105
|
+
end
|
106
|
+
@keywords_seen.add(obj.prefix)
|
107
|
+
end
|
108
|
+
|
109
|
+
# evidence always needs quoting; backwards-compatibility
|
110
|
+
if obj.is_a? Annotation
|
111
|
+
if obj.name == 'Evidence'
|
112
|
+
ev = obj.to_s
|
113
|
+
ev.gsub!(EvidenceMatcher, 'SET Evidence = "\1"')
|
114
|
+
puts ev.to_s
|
115
|
+
next
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
if obj.is_a? Parameter and obj.ns
|
120
|
+
# first try replacing by existing namespace prefix...
|
121
|
+
prefix = obj.ns.prefix.to_s
|
122
|
+
replacements = @change_log[prefix]
|
123
|
+
if replacements
|
124
|
+
replacement_value = replacements[obj.value]
|
125
|
+
if replacement_value
|
126
|
+
if LostReplaceValues.include? replacement_value
|
127
|
+
$stderr.puts "no replacement value for #{obj.ns} '#{obj.value}' - value '#{replacement_value}'"
|
128
|
+
else
|
129
|
+
obj.value = replacement_value
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# ...then change namespace if redefined...
|
135
|
+
if @redefine_section
|
136
|
+
redefinition = @redefine_section[prefix]
|
137
|
+
if redefinition
|
138
|
+
new_prefix = redefinition['new_keyword']
|
139
|
+
new_url = redefinition['new_url']
|
140
|
+
obj.ns = NamespaceDefinition.new(new_prefix, new_url)
|
141
|
+
|
142
|
+
# ...and replace value using new namespace prefix
|
143
|
+
replacements = @change_log[new_prefix]
|
144
|
+
if replacements
|
145
|
+
replacement_value = replacements[obj.value]
|
146
|
+
if replacement_value
|
147
|
+
if LostReplaceValues.include? replacement_value
|
148
|
+
$stderr.puts "no replacement value for #{obj.ns} '#{obj.value}' - value '#{replacement_value}'"
|
149
|
+
else
|
150
|
+
obj.value = replacement_value
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# do not print Parameter and Term; they are included in Statement
|
159
|
+
if not obj.is_a? Parameter and not obj.is_a? Term
|
160
|
+
puts obj.to_bel
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
def error_file(file_name)
|
168
|
+
$stderr.puts "#{file_name} is not readable"
|
169
|
+
exit 1
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
Main.new(content, changelog)
|
174
|
+
# vim: ts=2 sw=2:
|
175
|
+
# encoding: utf-8
|
@@ -0,0 +1,163 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# bel_upgrade_term: Upgrade BEL terms to a new set of resources.
|
3
|
+
#
|
4
|
+
# Terms as CLI option.
|
5
|
+
# usage: bel_upgrade_term -t "p(HGNC:A2LD1)" -n "1.0" -c change_log.json
|
6
|
+
#
|
7
|
+
# Terms from standard in.
|
8
|
+
# usage: echo -e "p(EGID:84)\np(HGNC:A2LD1)" | bel_upgrade_term -n "1.0" -c change_log.json
|
9
|
+
# usage: cat terms.bel | bel_upgrade_term -n "1.0" -c change_log.json
|
10
|
+
|
11
|
+
require 'bel'
|
12
|
+
require 'json'
|
13
|
+
require 'optparse'
|
14
|
+
require 'set'
|
15
|
+
require 'open-uri'
|
16
|
+
|
17
|
+
# setup and parse options
|
18
|
+
options = {}
|
19
|
+
OptionParser.new do |opts|
|
20
|
+
opts.banner = "Usage: bel_upgrade [options] [.bel file]"
|
21
|
+
opts.on('-t', '--terms TERM[\nTERM...]', 'BEL terms to upgrade (line-separated).') do |terms|
|
22
|
+
options[:terms] = terms
|
23
|
+
end
|
24
|
+
opts.on('-n', '--nsversion NAMESPACE VERSION', 'Assume BEL is described by this namespace version.') do |nsv|
|
25
|
+
options[:namespace_version] = nsv
|
26
|
+
end
|
27
|
+
opts.on("-c", "--changelog [FILE | URI]", "Change log JSON.") do |change_log|
|
28
|
+
options['change_log'] = change_log
|
29
|
+
end
|
30
|
+
end.parse!
|
31
|
+
|
32
|
+
# option guards
|
33
|
+
if not options[:namespace_version]
|
34
|
+
$stderr.puts "The --nsversion option is required. Use -h / --help for details."
|
35
|
+
exit 1
|
36
|
+
end
|
37
|
+
unless options[:terms] or not STDIN.tty?
|
38
|
+
$stderr.puts "No bel terms provided; try --term, or STDIN (standard in). Use -h / --help for details."
|
39
|
+
exit 1
|
40
|
+
end
|
41
|
+
unless options['change_log']
|
42
|
+
$stderr.puts "Missing --changelog option. Use -h / --help for details."
|
43
|
+
exit 1
|
44
|
+
end
|
45
|
+
if not File.exists? options['change_log']
|
46
|
+
begin
|
47
|
+
open(options['change_log']) do |f|
|
48
|
+
unless f.content_type == 'application/json'
|
49
|
+
$stderr.puts "Expected application/json content type, actual: #{f.content_type}"
|
50
|
+
exit 1
|
51
|
+
end
|
52
|
+
end
|
53
|
+
rescue OpenURI::HTTPError => e
|
54
|
+
$stderr.puts "Cannot read URI for change_log, #{options['change_log']}, status: #{e}"
|
55
|
+
exit 1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# read bel content
|
60
|
+
content =
|
61
|
+
if options[:terms]
|
62
|
+
options[:terms]
|
63
|
+
else
|
64
|
+
$stdin.read
|
65
|
+
end
|
66
|
+
|
67
|
+
if content.strip().empty?
|
68
|
+
$stderr.puts "Empty bel term content. Check input."
|
69
|
+
end
|
70
|
+
content += "\n"
|
71
|
+
|
72
|
+
# read change log
|
73
|
+
changelog = nil
|
74
|
+
if File.exists? options['change_log']
|
75
|
+
File.open(options['change_log']) do |f|
|
76
|
+
changelog = JSON.parse(f.read)
|
77
|
+
end
|
78
|
+
else
|
79
|
+
open(options['change_log']) do |file|
|
80
|
+
changelog = JSON.parse(file.read)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
unless changelog
|
85
|
+
$stderr.puts "Cannot retrieve change_log #{options['change_log']}"
|
86
|
+
end
|
87
|
+
|
88
|
+
class Main
|
89
|
+
|
90
|
+
LostReplaceValues = ['unresolved', 'withdrawn']
|
91
|
+
attr_reader :ttl
|
92
|
+
|
93
|
+
def initialize(nsversion, content, change_log)
|
94
|
+
@change_log = change_log
|
95
|
+
@redefine_section = @change_log['redefine']
|
96
|
+
resource_index = ResourceIndex.openbel_published_index(nsversion)
|
97
|
+
content.each_line do |line|
|
98
|
+
parsed_objects = BEL::Script.parse(line, resource_index).to_a
|
99
|
+
|
100
|
+
if parsed_objects.empty?
|
101
|
+
$stderr.puts "parse failure for '#{line.strip}': outputting original"
|
102
|
+
puts line
|
103
|
+
else
|
104
|
+
parsed_objects.each do |obj|
|
105
|
+
if obj.is_a? Parameter and obj.ns
|
106
|
+
# first try replacing by existing namespace prefix...
|
107
|
+
prefix = obj.ns.prefix.to_s
|
108
|
+
replacements = @change_log[prefix]
|
109
|
+
if replacements
|
110
|
+
replacement_value = replacements[obj.value]
|
111
|
+
if replacement_value
|
112
|
+
if LostReplaceValues.include? replacement_value
|
113
|
+
$stderr.puts "no replacement value for #{obj.ns} '#{obj.value}' - value '#{replacement_value}'"
|
114
|
+
else
|
115
|
+
obj.value = replacement_value
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# ...then change namespace if redefined...
|
121
|
+
if @redefine_section
|
122
|
+
redefinition = @redefine_section[prefix]
|
123
|
+
if redefinition
|
124
|
+
new_prefix = redefinition['new_keyword']
|
125
|
+
new_url = redefinition['new_url']
|
126
|
+
obj.ns = NamespaceDefinition.new(new_prefix, new_url)
|
127
|
+
|
128
|
+
# ...and replace value using new namespace prefix
|
129
|
+
replacements = @change_log[new_prefix]
|
130
|
+
if replacements
|
131
|
+
replacement_value = replacements[obj.value]
|
132
|
+
if replacement_value
|
133
|
+
if LostReplaceValues.include? replacement_value
|
134
|
+
$stderr.puts "no replacement value for #{obj.ns} '#{obj.value}' - value '#{replacement_value}'"
|
135
|
+
else
|
136
|
+
obj.value = replacement_value
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# do not print Parameter and Term; they are included in Statement
|
145
|
+
if obj.is_a? Statement
|
146
|
+
puts obj.to_bel
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def error_file(file_name)
|
156
|
+
$stderr.puts "#{file_name} is not readable"
|
157
|
+
exit 1
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
Main.new(options[:namespace_version], content, changelog)
|
162
|
+
# vim: ts=2 sw=2:
|
163
|
+
# encoding: utf-8
|
data/ext/mri/bel-ast.c
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
#include <stdlib.h>
|
2
|
+
#include <string.h>
|
3
|
+
#include <stdio.h>
|
4
|
+
#include "bel-ast.h"
|
5
|
+
|
6
|
+
bel_ast_node* bel_new_ast_node_token(bel_ast_token_type type) {
|
7
|
+
bel_ast_node* node;
|
8
|
+
node = malloc(sizeof(bel_ast_node));
|
9
|
+
node->token = malloc(sizeof(bel_ast_node_token));
|
10
|
+
node->token->type = BEL_TOKEN;
|
11
|
+
node->token->ttype = type;
|
12
|
+
node->token->left = NULL;
|
13
|
+
node->token->right = NULL;
|
14
|
+
return node;
|
15
|
+
};
|
16
|
+
|
17
|
+
bel_ast_node* bel_new_ast_node_value(bel_ast_value_type type, char* value) {
|
18
|
+
bel_ast_node* node;
|
19
|
+
char* copy_value;
|
20
|
+
|
21
|
+
if (value) {
|
22
|
+
copy_value = malloc(strlen(value) + 1);
|
23
|
+
strcpy(copy_value, value);
|
24
|
+
} else {
|
25
|
+
copy_value = NULL;
|
26
|
+
}
|
27
|
+
|
28
|
+
node = malloc(sizeof(bel_ast_node));
|
29
|
+
node->value = malloc(sizeof(bel_ast_node_value));
|
30
|
+
node->value->type = BEL_VALUE;
|
31
|
+
node->value->vtype = type;
|
32
|
+
node->value->value = copy_value;
|
33
|
+
return node;
|
34
|
+
};
|
35
|
+
|
36
|
+
bel_ast_node* bel_copy_ast_node(bel_ast_node* node) {
|
37
|
+
bel_ast_node* copy_node;
|
38
|
+
char* copy_value;
|
39
|
+
|
40
|
+
if (!node) {
|
41
|
+
return NULL;
|
42
|
+
}
|
43
|
+
|
44
|
+
copy_node = malloc(sizeof(bel_ast_node));
|
45
|
+
|
46
|
+
if (node->type_info->type == BEL_VALUE) {
|
47
|
+
if (node->value->value) {
|
48
|
+
copy_value = malloc(strlen(node->value->value) + 1);
|
49
|
+
strcpy(copy_value, node->value->value);
|
50
|
+
} else {
|
51
|
+
copy_value = NULL;
|
52
|
+
}
|
53
|
+
|
54
|
+
copy_node->value = malloc(sizeof(bel_ast_node_value));
|
55
|
+
copy_node->value->type = node->value->type;
|
56
|
+
copy_node->value->vtype = node->value->vtype;
|
57
|
+
copy_node->value->value = copy_value;
|
58
|
+
} else {
|
59
|
+
copy_node->token = malloc(sizeof(bel_ast_node_token));
|
60
|
+
copy_node->token->type = node->token->type;
|
61
|
+
copy_node->token->ttype = node->token->ttype;
|
62
|
+
copy_node->token->left = bel_copy_ast_node(node->token->left);
|
63
|
+
copy_node->token->right = bel_copy_ast_node(node->token->right);
|
64
|
+
}
|
65
|
+
|
66
|
+
return copy_node;
|
67
|
+
}
|
68
|
+
|
69
|
+
bel_ast_node* bel_set_value(bel_ast_node* node, char* value) {
|
70
|
+
char* copy_value;
|
71
|
+
|
72
|
+
if (!node) {
|
73
|
+
// TODO Debug node error to stderr; node is NULL
|
74
|
+
return NULL;
|
75
|
+
}
|
76
|
+
|
77
|
+
if (node->type_info->type != BEL_VALUE) {
|
78
|
+
// TODO Debug node error to stderr; node cannot hold value
|
79
|
+
return NULL;
|
80
|
+
}
|
81
|
+
|
82
|
+
if (value) {
|
83
|
+
copy_value = malloc(strlen(value) + 1);
|
84
|
+
strcpy(copy_value, value);
|
85
|
+
} else {
|
86
|
+
copy_value = NULL;
|
87
|
+
}
|
88
|
+
|
89
|
+
node->value->value = copy_value;
|
90
|
+
return node;
|
91
|
+
}
|
92
|
+
|
93
|
+
bel_ast* bel_new_ast() {
|
94
|
+
bel_ast* ast;
|
95
|
+
ast = malloc(sizeof(bel_ast));
|
96
|
+
ast->root = NULL;
|
97
|
+
return ast;
|
98
|
+
};
|
99
|
+
|
100
|
+
void bel_free_ast(bel_ast* ast) {
|
101
|
+
if (!ast) {
|
102
|
+
return;
|
103
|
+
}
|
104
|
+
bel_free_ast_node(ast->root);
|
105
|
+
free(ast);
|
106
|
+
};
|
107
|
+
|
108
|
+
void bel_free_ast_node(bel_ast_node* node) {
|
109
|
+
if (node->type_info->type == BEL_TOKEN) {
|
110
|
+
if (node->token->left != NULL) {
|
111
|
+
bel_free_ast_node(node->token->left);
|
112
|
+
}
|
113
|
+
if (node->token->right != NULL) {
|
114
|
+
bel_free_ast_node(node->token->right);
|
115
|
+
}
|
116
|
+
free(node->token);
|
117
|
+
} else {
|
118
|
+
free(node->value->value);
|
119
|
+
free(node->value);
|
120
|
+
}
|
121
|
+
|
122
|
+
free(node);
|
123
|
+
};
|
124
|
+
|
125
|
+
void bel_print_ast_node(bel_ast_node* node, char* tree_flat_string) {
|
126
|
+
char val[1024 * 32];
|
127
|
+
if (node == NULL) {
|
128
|
+
strcat(tree_flat_string, "(null) ");
|
129
|
+
return;
|
130
|
+
}
|
131
|
+
|
132
|
+
switch(node->type_info->type) {
|
133
|
+
case BEL_TOKEN:
|
134
|
+
switch(node->type_info->ttype) {
|
135
|
+
case BEL_TOKEN_ARG:
|
136
|
+
strcat(tree_flat_string, "ARG ");
|
137
|
+
break;
|
138
|
+
case BEL_TOKEN_NV:
|
139
|
+
strcat(tree_flat_string, "NV ");
|
140
|
+
break;
|
141
|
+
case BEL_TOKEN_TERM:
|
142
|
+
strcat(tree_flat_string, "TERM ");
|
143
|
+
break;
|
144
|
+
case BEL_TOKEN_SUBJECT:
|
145
|
+
strcat(tree_flat_string, "SUBJECT ");
|
146
|
+
break;
|
147
|
+
case BEL_TOKEN_REL:
|
148
|
+
strcat(tree_flat_string, "REL ");
|
149
|
+
break;
|
150
|
+
case BEL_TOKEN_OBJECT:
|
151
|
+
strcat(tree_flat_string, "OBJECT ");
|
152
|
+
break;
|
153
|
+
case BEL_TOKEN_STATEMENT:
|
154
|
+
strcat(tree_flat_string, "STATEMENT ");
|
155
|
+
break;
|
156
|
+
};
|
157
|
+
bel_print_ast_node(node->token->left, tree_flat_string);
|
158
|
+
bel_print_ast_node(node->token->right, tree_flat_string);
|
159
|
+
break;
|
160
|
+
case BEL_VALUE:
|
161
|
+
switch(node->type_info->vtype) {
|
162
|
+
case BEL_VALUE_FX:
|
163
|
+
if (node->value->value == NULL) {
|
164
|
+
strcat(tree_flat_string, "fx((null)) ");
|
165
|
+
} else {
|
166
|
+
sprintf(val, "fx(%s) ", node->value->value);
|
167
|
+
strcat(tree_flat_string, val);
|
168
|
+
}
|
169
|
+
break;
|
170
|
+
case BEL_VALUE_REL:
|
171
|
+
if (node->value->value == NULL) {
|
172
|
+
strcat(tree_flat_string, "rel((null)) ");
|
173
|
+
} else {
|
174
|
+
sprintf(val, "rel(%s) ", node->value->value);
|
175
|
+
strcat(tree_flat_string, val);
|
176
|
+
}
|
177
|
+
break;
|
178
|
+
case BEL_VALUE_PFX:
|
179
|
+
if (node->value->value == NULL) {
|
180
|
+
strcat(tree_flat_string, "pfx((null)) ");
|
181
|
+
} else {
|
182
|
+
sprintf(val, "pfx(%s) ", node->value->value);
|
183
|
+
strcat(tree_flat_string, val);
|
184
|
+
}
|
185
|
+
break;
|
186
|
+
case BEL_VALUE_VAL:
|
187
|
+
if (node->value->value == NULL) {
|
188
|
+
strcat(tree_flat_string, "val((null)) ");
|
189
|
+
} else {
|
190
|
+
sprintf(val, "val(%s) ", node->value->value);
|
191
|
+
strcat(tree_flat_string, val);
|
192
|
+
}
|
193
|
+
break;
|
194
|
+
};
|
195
|
+
break;
|
196
|
+
};
|
197
|
+
};
|
198
|
+
|
199
|
+
void bel_print_ast(bel_ast* ast) {
|
200
|
+
char tree_flat_string[1024 * 32];
|
201
|
+
|
202
|
+
if (!ast) {
|
203
|
+
return;
|
204
|
+
}
|
205
|
+
|
206
|
+
memset(tree_flat_string, '\0', 1024 * 32);
|
207
|
+
bel_print_ast_node(ast->root, tree_flat_string);
|
208
|
+
fprintf(stdout, "%s\n", tree_flat_string);
|
209
|
+
};
|
210
|
+
|
211
|
+
char* bel_ast_as_string(bel_ast* ast) {
|
212
|
+
char *tree_flat_string;
|
213
|
+
|
214
|
+
if (!ast) {
|
215
|
+
return NULL;
|
216
|
+
}
|
217
|
+
|
218
|
+
tree_flat_string = calloc(1024 * 32, 1);
|
219
|
+
bel_print_ast_node(ast->root, tree_flat_string);
|
220
|
+
return tree_flat_string;
|
221
|
+
};
|