Add methods for converting between Collections (asBag, asSet, etc)
[panda.git] / src / st-compiler.c
blobe4a3cd679a0cb6bb7bcadb05a9fcfa03d7152de4
2 #include "st-compiler.h"
3 #include "st-symbol.h"
4 #include "st-universe.h"
5 #include "st-dictionary.h"
6 #include "st-behavior.h"
7 #include "st-input.h"
8 #include "st-node.h"
10 #include "st-lexer.h"
11 #include "st-array.h"
13 #include <stdlib.h>
14 #include <ctype.h>
15 #include <string.h>
18 typedef struct {
20 const char *filename;
21 st_input *input;
23 int line;
25 } FileInParser;
28 * st_compile_string:
29 * @class: The class for which the compiled method will be bound.
30 * @string: Source code for the method
31 * @error: return location for errors
33 * This function will compile a source string into a new CompiledMethod,
34 * and place the method in the methodDictionary of the given class.
36 bool
37 st_compile_string (st_oop class, const char *string, st_compiler_error *error)
39 st_node *node;
40 st_oop method;
41 st_lexer *lexer;
43 st_assert (class != ST_NIL);
45 lexer = st_lexer_new (string);
46 if (!lexer)
47 return false;
49 node = st_parser_parse (lexer, error);
50 st_lexer_destroy (lexer);
52 if (!node)
53 return false;
55 method = st_generate_method (class, node, error);
56 if (method == ST_NIL) {
57 st_node_destroy (node);
58 return false;
61 st_dictionary_at_put (ST_BEHAVIOR (class)->method_dictionary,
62 node->method.selector,
63 method);
65 st_node_destroy (node);
67 return true;
70 static void
71 filein_error (FileInParser *parser, st_token *token, const char *message)
73 fprintf (stderr, "%s: %i: %s\n", parser->filename, parser->line + ((token) ? st_token_get_line (token) : -90), message);
74 exit (1);
78 static st_token *
79 next_token (FileInParser *parser, st_lexer *lexer)
81 st_token *token;
83 token = st_lexer_next_token (lexer);
85 if (st_token_get_type (token) == ST_TOKEN_COMMENT)
86 return next_token (parser, lexer);
87 else if (st_token_get_type (token) == ST_TOKEN_INVALID)
88 filein_error (parser, token, st_lexer_error_message (lexer));
90 return token;
94 static st_lexer *
95 next_chunk (FileInParser *parser)
97 st_lexer *lexer;
98 char *chunk;
100 parser->line = st_input_get_line (parser->input);
102 chunk = st_input_next_chunk (parser->input);
103 if (!chunk)
104 return NULL;
106 lexer = st_lexer_new (chunk);
108 st_free (chunk);
109 return lexer;
112 static void
113 parse_method (FileInParser *parser,
114 st_lexer *lexer,
115 char *class_name,
116 bool class_method)
118 st_token *token = NULL;
119 st_oop class;
120 st_compiler_error error;
122 st_lexer_destroy (lexer);
124 /* get class or metaclass */
125 class = st_global_get (class_name);
126 if (class == ST_NIL)
127 filein_error (parser, token, "undefined class");
129 if (class_method)
130 class = st_object_class (class);
132 /* parse method chunk */
133 lexer = next_chunk (parser);
134 if (!lexer)
135 filein_error (parser, token, "expected method definition");
137 st_node *node;
138 st_oop method;
140 node = st_parser_parse (lexer, &error);
141 if (node == NULL)
142 goto error;
143 if (node->type != ST_METHOD_NODE)
144 printf ("%i\n", node->type);
146 method = st_generate_method (class, node, &error);
147 if (method == ST_NIL)
148 goto error;
150 st_dictionary_at_put (ST_BEHAVIOR (class)->method_dictionary,
151 node->method.selector,
152 method);
155 st_node_destroy (node);
156 st_lexer_destroy (lexer);
157 st_free (class_name);
159 return;
161 error:
162 st_node_destroy (node);
163 fprintf (stderr, "%s:%i: %s\n", parser->filename,
164 parser->line + error.line - 1 ,
165 error.message);
166 exit (1);
169 static void
170 parse_class (FileInParser *parser, st_lexer *lexer, char *name)
176 static void
177 parse_chunk (FileInParser *parser, st_lexer *lexer)
179 st_token *token;
180 char *name;
182 token = next_token (parser, lexer);
184 if (st_token_get_type (token) == ST_TOKEN_IDENTIFIER) {
186 name = st_strdup (st_token_get_text (token));
188 token = next_token (parser, lexer);
190 if (st_token_get_type (token) == ST_TOKEN_IDENTIFIER
191 && (streq (st_token_get_text (token), "method")))
193 parse_method (parser, lexer, name, false);
195 else if (st_token_get_type (token) == ST_TOKEN_IDENTIFIER
196 || streq (st_token_get_text (token), "classMethod"))
198 parse_method (parser, lexer, name, true);
200 else if (st_token_get_type (token) == ST_TOKEN_KEYWORD_SELECTOR
201 && streq (st_token_get_text (token), "subclass:"))
203 parse_class (parser, lexer, name);
205 else if (streq (name, "Annotation") &&
206 st_token_get_type (token) == ST_TOKEN_KEYWORD_SELECTOR &&
207 streq (st_token_get_text (token), "key:")) {
209 return;
212 else
213 goto error;
215 } else
216 goto error;
218 return;
220 error:
222 filein_error (parser, token, "unrecognised syntax");
225 static void
226 parse_chunks (FileInParser *parser)
228 st_lexer *lexer;
230 while (st_input_look_ahead (parser->input, 1) != ST_INPUT_EOF) {
232 lexer = next_chunk (parser);
233 if (!lexer)
234 continue;
236 parse_chunk (parser, lexer);
240 /* isn't declared in glibc string.h */
241 char * basename (const char *FILENAME);
243 void
244 st_compile_file_in (const char *filename)
246 char *buffer;
247 FileInParser *parser;
249 st_assert (filename != NULL);
251 if (!st_file_get_contents (filename, &buffer)) {
252 return;
255 parser = st_new0 (FileInParser);
257 parser->input = st_input_new (buffer);
258 if (!parser->input) {
259 fprintf (stderr, "could not validate input file '%s'", filename);
260 return;
263 parser->filename = basename (filename);
264 parser->line = 1;
266 parse_chunks (parser);
268 st_free (buffer);
269 st_input_destroy (parser->input);
270 st_free (parser);