├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── moonshot.svg
├── src
├── entities.c
├── internal.h
├── list.c
├── map.c
├── moonshot.c
├── moonshot.h
├── nodes.c
├── parser.c
├── scopes.c
├── tokenizer.c
├── traversal.c
└── types.c
├── testing
├── outputs
│ ├── basic.txt
│ ├── chaining.txt
│ ├── class.txt
│ ├── classes.txt
│ ├── comments.txt
│ ├── functions.txt
│ ├── ifchains.txt
│ ├── operators.txt
│ ├── reference.txt
│ ├── require.txt
│ ├── syntax.txt
│ ├── trust.txt
│ └── variadic.txt
├── queries
│ ├── basic.lua
│ ├── chaining.moon
│ ├── class.moon
│ ├── classes.moon
│ ├── comments.moon
│ ├── functions.moon
│ ├── ifchains.moon
│ ├── operators.lua
│ ├── reference.moon
│ ├── require.moon
│ ├── syntax.moon
│ ├── trust.moon
│ └── variadic.moon
└── run
└── tools
└── cli.c
/.gitignore:
--------------------------------------------------------------------------------
1 | /moonshot
2 | /*.lua
3 | /bin
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 |
3 | Moonshot is Copyright (C) 2021 LugoCorp, LLC
4 | Contact: http://lugocorp.net
5 |
6 | You may use, distribute and copy Moonshot under the terms of
7 | this license.
8 |
9 | -------------------------------------------------------------------------
10 |
11 | GNU GENERAL PUBLIC LICENSE
12 | Version 3, 29 June 2007
13 |
14 | Copyright (C) 2007 Free Software Foundation, Inc.
15 | Everyone is permitted to copy and distribute verbatim copies
16 | of this license document, but changing it is not allowed.
17 |
18 | Preamble
19 |
20 | The GNU General Public License is a free, copyleft license for
21 | software and other kinds of works.
22 |
23 | The licenses for most software and other practical works are designed
24 | to take away your freedom to share and change the works. By contrast,
25 | the GNU General Public License is intended to guarantee your freedom to
26 | share and change all versions of a program--to make sure it remains free
27 | software for all its users. We, the Free Software Foundation, use the
28 | GNU General Public License for most of our software; it applies also to
29 | any other work released this way by its authors. You can apply it to
30 | your programs, too.
31 |
32 | When we speak of free software, we are referring to freedom, not
33 | price. Our General Public Licenses are designed to make sure that you
34 | have the freedom to distribute copies of free software (and charge for
35 | them if you wish), that you receive source code or can get it if you
36 | want it, that you can change the software or use pieces of it in new
37 | free programs, and that you know you can do these things.
38 |
39 | To protect your rights, we need to prevent others from denying you
40 | these rights or asking you to surrender the rights. Therefore, you have
41 | certain responsibilities if you distribute copies of the software, or if
42 | you modify it: responsibilities to respect the freedom of others.
43 |
44 | For example, if you distribute copies of such a program, whether
45 | gratis or for a fee, you must pass on to the recipients the same
46 | freedoms that you received. You must make sure that they, too, receive
47 | or can get the source code. And you must show them these terms so they
48 | know their rights.
49 |
50 | Developers that use the GNU GPL protect your rights with two steps:
51 | (1) assert copyright on the software, and (2) offer you this License
52 | giving you legal permission to copy, distribute and/or modify it.
53 |
54 | For the developers' and authors' protection, the GPL clearly explains
55 | that there is no warranty for this free software. For both users' and
56 | authors' sake, the GPL requires that modified versions be marked as
57 | changed, so that their problems will not be attributed erroneously to
58 | authors of previous versions.
59 |
60 | Some devices are designed to deny users access to install or run
61 | modified versions of the software inside them, although the manufacturer
62 | can do so. This is fundamentally incompatible with the aim of
63 | protecting users' freedom to change the software. The systematic
64 | pattern of such abuse occurs in the area of products for individuals to
65 | use, which is precisely where it is most unacceptable. Therefore, we
66 | have designed this version of the GPL to prohibit the practice for those
67 | products. If such problems arise substantially in other domains, we
68 | stand ready to extend this provision to those domains in future versions
69 | of the GPL, as needed to protect the freedom of users.
70 |
71 | Finally, every program is threatened constantly by software patents.
72 | States should not allow patents to restrict development and use of
73 | software on general-purpose computers, but in those that do, we wish to
74 | avoid the special danger that patents applied to a free program could
75 | make it effectively proprietary. To prevent this, the GPL assures that
76 | patents cannot be used to render the program non-free.
77 |
78 | The precise terms and conditions for copying, distribution and
79 | modification follow.
80 |
81 | TERMS AND CONDITIONS
82 |
83 | 0. Definitions.
84 |
85 | "This License" refers to version 3 of the GNU General Public License.
86 |
87 | "Copyright" also means copyright-like laws that apply to other kinds of
88 | works, such as semiconductor masks.
89 |
90 | "The Program" refers to any copyrightable work licensed under this
91 | License. Each licensee is addressed as "you". "Licensees" and
92 | "recipients" may be individuals or organizations.
93 |
94 | To "modify" a work means to copy from or adapt all or part of the work
95 | in a fashion requiring copyright permission, other than the making of an
96 | exact copy. The resulting work is called a "modified version" of the
97 | earlier work or a work "based on" the earlier work.
98 |
99 | A "covered work" means either the unmodified Program or a work based
100 | on the Program.
101 |
102 | To "propagate" a work means to do anything with it that, without
103 | permission, would make you directly or secondarily liable for
104 | infringement under applicable copyright law, except executing it on a
105 | computer or modifying a private copy. Propagation includes copying,
106 | distribution (with or without modification), making available to the
107 | public, and in some countries other activities as well.
108 |
109 | To "convey" a work means any kind of propagation that enables other
110 | parties to make or receive copies. Mere interaction with a user through
111 | a computer network, with no transfer of a copy, is not conveying.
112 |
113 | An interactive user interface displays "Appropriate Legal Notices"
114 | to the extent that it includes a convenient and prominently visible
115 | feature that (1) displays an appropriate copyright notice, and (2)
116 | tells the user that there is no warranty for the work (except to the
117 | extent that warranties are provided), that licensees may convey the
118 | work under this License, and how to view a copy of this License. If
119 | the interface presents a list of user commands or options, such as a
120 | menu, a prominent item in the list meets this criterion.
121 |
122 | 1. Source Code.
123 |
124 | The "source code" for a work means the preferred form of the work
125 | for making modifications to it. "Object code" means any non-source
126 | form of a work.
127 |
128 | A "Standard Interface" means an interface that either is an official
129 | standard defined by a recognized standards body, or, in the case of
130 | interfaces specified for a particular programming language, one that
131 | is widely used among developers working in that language.
132 |
133 | The "System Libraries" of an executable work include anything, other
134 | than the work as a whole, that (a) is included in the normal form of
135 | packaging a Major Component, but which is not part of that Major
136 | Component, and (b) serves only to enable use of the work with that
137 | Major Component, or to implement a Standard Interface for which an
138 | implementation is available to the public in source code form. A
139 | "Major Component", in this context, means a major essential component
140 | (kernel, window system, and so on) of the specific operating system
141 | (if any) on which the executable work runs, or a compiler used to
142 | produce the work, or an object code interpreter used to run it.
143 |
144 | The "Corresponding Source" for a work in object code form means all
145 | the source code needed to generate, install, and (for an executable
146 | work) run the object code and to modify the work, including scripts to
147 | control those activities. However, it does not include the work's
148 | System Libraries, or general-purpose tools or generally available free
149 | programs which are used unmodified in performing those activities but
150 | which are not part of the work. For example, Corresponding Source
151 | includes interface definition files associated with source files for
152 | the work, and the source code for shared libraries and dynamically
153 | linked subprograms that the work is specifically designed to require,
154 | such as by intimate data communication or control flow between those
155 | subprograms and other parts of the work.
156 |
157 | The Corresponding Source need not include anything that users
158 | can regenerate automatically from other parts of the Corresponding
159 | Source.
160 |
161 | The Corresponding Source for a work in source code form is that
162 | same work.
163 |
164 | 2. Basic Permissions.
165 |
166 | All rights granted under this License are granted for the term of
167 | copyright on the Program, and are irrevocable provided the stated
168 | conditions are met. This License explicitly affirms your unlimited
169 | permission to run the unmodified Program. The output from running a
170 | covered work is covered by this License only if the output, given its
171 | content, constitutes a covered work. This License acknowledges your
172 | rights of fair use or other equivalent, as provided by copyright law.
173 |
174 | You may make, run and propagate covered works that you do not
175 | convey, without conditions so long as your license otherwise remains
176 | in force. You may convey covered works to others for the sole purpose
177 | of having them make modifications exclusively for you, or provide you
178 | with facilities for running those works, provided that you comply with
179 | the terms of this License in conveying all material for which you do
180 | not control copyright. Those thus making or running the covered works
181 | for you must do so exclusively on your behalf, under your direction
182 | and control, on terms that prohibit them from making any copies of
183 | your copyrighted material outside their relationship with you.
184 |
185 | Conveying under any other circumstances is permitted solely under
186 | the conditions stated below. Sublicensing is not allowed; section 10
187 | makes it unnecessary.
188 |
189 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
190 |
191 | No covered work shall be deemed part of an effective technological
192 | measure under any applicable law fulfilling obligations under article
193 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
194 | similar laws prohibiting or restricting circumvention of such
195 | measures.
196 |
197 | When you convey a covered work, you waive any legal power to forbid
198 | circumvention of technological measures to the extent such circumvention
199 | is effected by exercising rights under this License with respect to
200 | the covered work, and you disclaim any intention to limit operation or
201 | modification of the work as a means of enforcing, against the work's
202 | users, your or third parties' legal rights to forbid circumvention of
203 | technological measures.
204 |
205 | 4. Conveying Verbatim Copies.
206 |
207 | You may convey verbatim copies of the Program's source code as you
208 | receive it, in any medium, provided that you conspicuously and
209 | appropriately publish on each copy an appropriate copyright notice;
210 | keep intact all notices stating that this License and any
211 | non-permissive terms added in accord with section 7 apply to the code;
212 | keep intact all notices of the absence of any warranty; and give all
213 | recipients a copy of this License along with the Program.
214 |
215 | You may charge any price or no price for each copy that you convey,
216 | and you may offer support or warranty protection for a fee.
217 |
218 | 5. Conveying Modified Source Versions.
219 |
220 | You may convey a work based on the Program, or the modifications to
221 | produce it from the Program, in the form of source code under the
222 | terms of section 4, provided that you also meet all of these conditions:
223 |
224 | a) The work must carry prominent notices stating that you modified
225 | it, and giving a relevant date.
226 |
227 | b) The work must carry prominent notices stating that it is
228 | released under this License and any conditions added under section
229 | 7. This requirement modifies the requirement in section 4 to
230 | "keep intact all notices".
231 |
232 | c) You must license the entire work, as a whole, under this
233 | License to anyone who comes into possession of a copy. This
234 | License will therefore apply, along with any applicable section 7
235 | additional terms, to the whole of the work, and all its parts,
236 | regardless of how they are packaged. This License gives no
237 | permission to license the work in any other way, but it does not
238 | invalidate such permission if you have separately received it.
239 |
240 | d) If the work has interactive user interfaces, each must display
241 | Appropriate Legal Notices; however, if the Program has interactive
242 | interfaces that do not display Appropriate Legal Notices, your
243 | work need not make them do so.
244 |
245 | A compilation of a covered work with other separate and independent
246 | works, which are not by their nature extensions of the covered work,
247 | and which are not combined with it such as to form a larger program,
248 | in or on a volume of a storage or distribution medium, is called an
249 | "aggregate" if the compilation and its resulting copyright are not
250 | used to limit the access or legal rights of the compilation's users
251 | beyond what the individual works permit. Inclusion of a covered work
252 | in an aggregate does not cause this License to apply to the other
253 | parts of the aggregate.
254 |
255 | 6. Conveying Non-Source Forms.
256 |
257 | You may convey a covered work in object code form under the terms
258 | of sections 4 and 5, provided that you also convey the
259 | machine-readable Corresponding Source under the terms of this License,
260 | in one of these ways:
261 |
262 | a) Convey the object code in, or embodied in, a physical product
263 | (including a physical distribution medium), accompanied by the
264 | Corresponding Source fixed on a durable physical medium
265 | customarily used for software interchange.
266 |
267 | b) Convey the object code in, or embodied in, a physical product
268 | (including a physical distribution medium), accompanied by a
269 | written offer, valid for at least three years and valid for as
270 | long as you offer spare parts or customer support for that product
271 | model, to give anyone who possesses the object code either (1) a
272 | copy of the Corresponding Source for all the software in the
273 | product that is covered by this License, on a durable physical
274 | medium customarily used for software interchange, for a price no
275 | more than your reasonable cost of physically performing this
276 | conveying of source, or (2) access to copy the
277 | Corresponding Source from a network server at no charge.
278 |
279 | c) Convey individual copies of the object code with a copy of the
280 | written offer to provide the Corresponding Source. This
281 | alternative is allowed only occasionally and noncommercially, and
282 | only if you received the object code with such an offer, in accord
283 | with subsection 6b.
284 |
285 | d) Convey the object code by offering access from a designated
286 | place (gratis or for a charge), and offer equivalent access to the
287 | Corresponding Source in the same way through the same place at no
288 | further charge. You need not require recipients to copy the
289 | Corresponding Source along with the object code. If the place to
290 | copy the object code is a network server, the Corresponding Source
291 | may be on a different server (operated by you or a third party)
292 | that supports equivalent copying facilities, provided you maintain
293 | clear directions next to the object code saying where to find the
294 | Corresponding Source. Regardless of what server hosts the
295 | Corresponding Source, you remain obligated to ensure that it is
296 | available for as long as needed to satisfy these requirements.
297 |
298 | e) Convey the object code using peer-to-peer transmission, provided
299 | you inform other peers where the object code and Corresponding
300 | Source of the work are being offered to the general public at no
301 | charge under subsection 6d.
302 |
303 | A separable portion of the object code, whose source code is excluded
304 | from the Corresponding Source as a System Library, need not be
305 | included in conveying the object code work.
306 |
307 | A "User Product" is either (1) a "consumer product", which means any
308 | tangible personal property which is normally used for personal, family,
309 | or household purposes, or (2) anything designed or sold for incorporation
310 | into a dwelling. In determining whether a product is a consumer product,
311 | doubtful cases shall be resolved in favor of coverage. For a particular
312 | product received by a particular user, "normally used" refers to a
313 | typical or common use of that class of product, regardless of the status
314 | of the particular user or of the way in which the particular user
315 | actually uses, or expects or is expected to use, the product. A product
316 | is a consumer product regardless of whether the product has substantial
317 | commercial, industrial or non-consumer uses, unless such uses represent
318 | the only significant mode of use of the product.
319 |
320 | "Installation Information" for a User Product means any methods,
321 | procedures, authorization keys, or other information required to install
322 | and execute modified versions of a covered work in that User Product from
323 | a modified version of its Corresponding Source. The information must
324 | suffice to ensure that the continued functioning of the modified object
325 | code is in no case prevented or interfered with solely because
326 | modification has been made.
327 |
328 | If you convey an object code work under this section in, or with, or
329 | specifically for use in, a User Product, and the conveying occurs as
330 | part of a transaction in which the right of possession and use of the
331 | User Product is transferred to the recipient in perpetuity or for a
332 | fixed term (regardless of how the transaction is characterized), the
333 | Corresponding Source conveyed under this section must be accompanied
334 | by the Installation Information. But this requirement does not apply
335 | if neither you nor any third party retains the ability to install
336 | modified object code on the User Product (for example, the work has
337 | been installed in ROM).
338 |
339 | The requirement to provide Installation Information does not include a
340 | requirement to continue to provide support service, warranty, or updates
341 | for a work that has been modified or installed by the recipient, or for
342 | the User Product in which it has been modified or installed. Access to a
343 | network may be denied when the modification itself materially and
344 | adversely affects the operation of the network or violates the rules and
345 | protocols for communication across the network.
346 |
347 | Corresponding Source conveyed, and Installation Information provided,
348 | in accord with this section must be in a format that is publicly
349 | documented (and with an implementation available to the public in
350 | source code form), and must require no special password or key for
351 | unpacking, reading or copying.
352 |
353 | 7. Additional Terms.
354 |
355 | "Additional permissions" are terms that supplement the terms of this
356 | License by making exceptions from one or more of its conditions.
357 | Additional permissions that are applicable to the entire Program shall
358 | be treated as though they were included in this License, to the extent
359 | that they are valid under applicable law. If additional permissions
360 | apply only to part of the Program, that part may be used separately
361 | under those permissions, but the entire Program remains governed by
362 | this License without regard to the additional permissions.
363 |
364 | When you convey a copy of a covered work, you may at your option
365 | remove any additional permissions from that copy, or from any part of
366 | it. (Additional permissions may be written to require their own
367 | removal in certain cases when you modify the work.) You may place
368 | additional permissions on material, added by you to a covered work,
369 | for which you have or can give appropriate copyright permission.
370 |
371 | Notwithstanding any other provision of this License, for material you
372 | add to a covered work, you may (if authorized by the copyright holders of
373 | that material) supplement the terms of this License with terms:
374 |
375 | a) Disclaiming warranty or limiting liability differently from the
376 | terms of sections 15 and 16 of this License; or
377 |
378 | b) Requiring preservation of specified reasonable legal notices or
379 | author attributions in that material or in the Appropriate Legal
380 | Notices displayed by works containing it; or
381 |
382 | c) Prohibiting misrepresentation of the origin of that material, or
383 | requiring that modified versions of such material be marked in
384 | reasonable ways as different from the original version; or
385 |
386 | d) Limiting the use for publicity purposes of names of licensors or
387 | authors of the material; or
388 |
389 | e) Declining to grant rights under trademark law for use of some
390 | trade names, trademarks, or service marks; or
391 |
392 | f) Requiring indemnification of licensors and authors of that
393 | material by anyone who conveys the material (or modified versions of
394 | it) with contractual assumptions of liability to the recipient, for
395 | any liability that these contractual assumptions directly impose on
396 | those licensors and authors.
397 |
398 | All other non-permissive additional terms are considered "further
399 | restrictions" within the meaning of section 10. If the Program as you
400 | received it, or any part of it, contains a notice stating that it is
401 | governed by this License along with a term that is a further
402 | restriction, you may remove that term. If a license document contains
403 | a further restriction but permits relicensing or conveying under this
404 | License, you may add to a covered work material governed by the terms
405 | of that license document, provided that the further restriction does
406 | not survive such relicensing or conveying.
407 |
408 | If you add terms to a covered work in accord with this section, you
409 | must place, in the relevant source files, a statement of the
410 | additional terms that apply to those files, or a notice indicating
411 | where to find the applicable terms.
412 |
413 | Additional terms, permissive or non-permissive, may be stated in the
414 | form of a separately written license, or stated as exceptions;
415 | the above requirements apply either way.
416 |
417 | 8. Termination.
418 |
419 | You may not propagate or modify a covered work except as expressly
420 | provided under this License. Any attempt otherwise to propagate or
421 | modify it is void, and will automatically terminate your rights under
422 | this License (including any patent licenses granted under the third
423 | paragraph of section 11).
424 |
425 | However, if you cease all violation of this License, then your
426 | license from a particular copyright holder is reinstated (a)
427 | provisionally, unless and until the copyright holder explicitly and
428 | finally terminates your license, and (b) permanently, if the copyright
429 | holder fails to notify you of the violation by some reasonable means
430 | prior to 60 days after the cessation.
431 |
432 | Moreover, your license from a particular copyright holder is
433 | reinstated permanently if the copyright holder notifies you of the
434 | violation by some reasonable means, this is the first time you have
435 | received notice of violation of this License (for any work) from that
436 | copyright holder, and you cure the violation prior to 30 days after
437 | your receipt of the notice.
438 |
439 | Termination of your rights under this section does not terminate the
440 | licenses of parties who have received copies or rights from you under
441 | this License. If your rights have been terminated and not permanently
442 | reinstated, you do not qualify to receive new licenses for the same
443 | material under section 10.
444 |
445 | 9. Acceptance Not Required for Having Copies.
446 |
447 | You are not required to accept this License in order to receive or
448 | run a copy of the Program. Ancillary propagation of a covered work
449 | occurring solely as a consequence of using peer-to-peer transmission
450 | to receive a copy likewise does not require acceptance. However,
451 | nothing other than this License grants you permission to propagate or
452 | modify any covered work. These actions infringe copyright if you do
453 | not accept this License. Therefore, by modifying or propagating a
454 | covered work, you indicate your acceptance of this License to do so.
455 |
456 | 10. Automatic Licensing of Downstream Recipients.
457 |
458 | Each time you convey a covered work, the recipient automatically
459 | receives a license from the original licensors, to run, modify and
460 | propagate that work, subject to this License. You are not responsible
461 | for enforcing compliance by third parties with this License.
462 |
463 | An "entity transaction" is a transaction transferring control of an
464 | organization, or substantially all assets of one, or subdividing an
465 | organization, or merging organizations. If propagation of a covered
466 | work results from an entity transaction, each party to that
467 | transaction who receives a copy of the work also receives whatever
468 | licenses to the work the party's predecessor in interest had or could
469 | give under the previous paragraph, plus a right to possession of the
470 | Corresponding Source of the work from the predecessor in interest, if
471 | the predecessor has it or can get it with reasonable efforts.
472 |
473 | You may not impose any further restrictions on the exercise of the
474 | rights granted or affirmed under this License. For example, you may
475 | not impose a license fee, royalty, or other charge for exercise of
476 | rights granted under this License, and you may not initiate litigation
477 | (including a cross-claim or counterclaim in a lawsuit) alleging that
478 | any patent claim is infringed by making, using, selling, offering for
479 | sale, or importing the Program or any portion of it.
480 |
481 | 11. Patents.
482 |
483 | A "contributor" is a copyright holder who authorizes use under this
484 | License of the Program or a work on which the Program is based. The
485 | work thus licensed is called the contributor's "contributor version".
486 |
487 | A contributor's "essential patent claims" are all patent claims
488 | owned or controlled by the contributor, whether already acquired or
489 | hereafter acquired, that would be infringed by some manner, permitted
490 | by this License, of making, using, or selling its contributor version,
491 | but do not include claims that would be infringed only as a
492 | consequence of further modification of the contributor version. For
493 | purposes of this definition, "control" includes the right to grant
494 | patent sublicenses in a manner consistent with the requirements of
495 | this License.
496 |
497 | Each contributor grants you a non-exclusive, worldwide, royalty-free
498 | patent license under the contributor's essential patent claims, to
499 | make, use, sell, offer for sale, import and otherwise run, modify and
500 | propagate the contents of its contributor version.
501 |
502 | In the following three paragraphs, a "patent license" is any express
503 | agreement or commitment, however denominated, not to enforce a patent
504 | (such as an express permission to practice a patent or covenant not to
505 | sue for patent infringement). To "grant" such a patent license to a
506 | party means to make such an agreement or commitment not to enforce a
507 | patent against the party.
508 |
509 | If you convey a covered work, knowingly relying on a patent license,
510 | and the Corresponding Source of the work is not available for anyone
511 | to copy, free of charge and under the terms of this License, through a
512 | publicly available network server or other readily accessible means,
513 | then you must either (1) cause the Corresponding Source to be so
514 | available, or (2) arrange to deprive yourself of the benefit of the
515 | patent license for this particular work, or (3) arrange, in a manner
516 | consistent with the requirements of this License, to extend the patent
517 | license to downstream recipients. "Knowingly relying" means you have
518 | actual knowledge that, but for the patent license, your conveying the
519 | covered work in a country, or your recipient's use of the covered work
520 | in a country, would infringe one or more identifiable patents in that
521 | country that you have reason to believe are valid.
522 |
523 | If, pursuant to or in connection with a single transaction or
524 | arrangement, you convey, or propagate by procuring conveyance of, a
525 | covered work, and grant a patent license to some of the parties
526 | receiving the covered work authorizing them to use, propagate, modify
527 | or convey a specific copy of the covered work, then the patent license
528 | you grant is automatically extended to all recipients of the covered
529 | work and works based on it.
530 |
531 | A patent license is "discriminatory" if it does not include within
532 | the scope of its coverage, prohibits the exercise of, or is
533 | conditioned on the non-exercise of one or more of the rights that are
534 | specifically granted under this License. You may not convey a covered
535 | work if you are a party to an arrangement with a third party that is
536 | in the business of distributing software, under which you make payment
537 | to the third party based on the extent of your activity of conveying
538 | the work, and under which the third party grants, to any of the
539 | parties who would receive the covered work from you, a discriminatory
540 | patent license (a) in connection with copies of the covered work
541 | conveyed by you (or copies made from those copies), or (b) primarily
542 | for and in connection with specific products or compilations that
543 | contain the covered work, unless you entered into that arrangement,
544 | or that patent license was granted, prior to 28 March 2007.
545 |
546 | Nothing in this License shall be construed as excluding or limiting
547 | any implied license or other defenses to infringement that may
548 | otherwise be available to you under applicable patent law.
549 |
550 | 12. No Surrender of Others' Freedom.
551 |
552 | If conditions are imposed on you (whether by court order, agreement or
553 | otherwise) that contradict the conditions of this License, they do not
554 | excuse you from the conditions of this License. If you cannot convey a
555 | covered work so as to satisfy simultaneously your obligations under this
556 | License and any other pertinent obligations, then as a consequence you may
557 | not convey it at all. For example, if you agree to terms that obligate you
558 | to collect a royalty for further conveying from those to whom you convey
559 | the Program, the only way you could satisfy both those terms and this
560 | License would be to refrain entirely from conveying the Program.
561 |
562 | 13. Use with the GNU Affero General Public License.
563 |
564 | Notwithstanding any other provision of this License, you have
565 | permission to link or combine any covered work with a work licensed
566 | under version 3 of the GNU Affero General Public License into a single
567 | combined work, and to convey the resulting work. The terms of this
568 | License will continue to apply to the part which is the covered work,
569 | but the special requirements of the GNU Affero General Public License,
570 | section 13, concerning interaction through a network will apply to the
571 | combination as such.
572 |
573 | 14. Revised Versions of this License.
574 |
575 | The Free Software Foundation may publish revised and/or new versions of
576 | the GNU General Public License from time to time. Such new versions will
577 | be similar in spirit to the present version, but may differ in detail to
578 | address new problems or concerns.
579 |
580 | Each version is given a distinguishing version number. If the
581 | Program specifies that a certain numbered version of the GNU General
582 | Public License "or any later version" applies to it, you have the
583 | option of following the terms and conditions either of that numbered
584 | version or of any later version published by the Free Software
585 | Foundation. If the Program does not specify a version number of the
586 | GNU General Public License, you may choose any version ever published
587 | by the Free Software Foundation.
588 |
589 | If the Program specifies that a proxy can decide which future
590 | versions of the GNU General Public License can be used, that proxy's
591 | public statement of acceptance of a version permanently authorizes you
592 | to choose that version for the Program.
593 |
594 | Later license versions may give you additional or different
595 | permissions. However, no additional obligations are imposed on any
596 | author or copyright holder as a result of your choosing to follow a
597 | later version.
598 |
599 | 15. Disclaimer of Warranty.
600 |
601 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
602 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
603 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
604 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
605 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
606 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
607 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
608 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
609 |
610 | 16. Limitation of Liability.
611 |
612 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
613 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
614 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
615 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
616 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
617 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
618 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
619 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
620 | SUCH DAMAGES.
621 |
622 | 17. Interpretation of Sections 15 and 16.
623 |
624 | If the disclaimer of warranty and limitation of liability provided
625 | above cannot be given local legal effect according to their terms,
626 | reviewing courts shall apply local law that most closely approximates
627 | an absolute waiver of all civil liability in connection with the
628 | Program, unless a warranty or assumption of liability accompanies a
629 | copy of the Program in return for a fee.
630 |
631 | END OF TERMS AND CONDITIONS
632 |
633 | How to Apply These Terms to Your New Programs
634 |
635 | If you develop a new program, and you want it to be of the greatest
636 | possible use to the public, the best way to achieve this is to make it
637 | free software which everyone can redistribute and change under these terms.
638 |
639 | To do so, attach the following notices to the program. It is safest
640 | to attach them to the start of each source file to most effectively
641 | state the exclusion of warranty; and each file should have at least
642 | the "copyright" line and a pointer to where the full notice is found.
643 |
644 |
645 | Copyright (C)
646 |
647 | This program is free software: you can redistribute it and/or modify
648 | it under the terms of the GNU General Public License as published by
649 | the Free Software Foundation, either version 3 of the License, or
650 | (at your option) any later version.
651 |
652 | This program is distributed in the hope that it will be useful,
653 | but WITHOUT ANY WARRANTY; without even the implied warranty of
654 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
655 | GNU General Public License for more details.
656 |
657 | You should have received a copy of the GNU General Public License
658 | along with this program. If not, see .
659 |
660 | Also add information on how to contact you by electronic and paper mail.
661 |
662 | If the program does terminal interaction, make it output a short
663 | notice like this when it starts in an interactive mode:
664 |
665 | Copyright (C)
666 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
667 | This is free software, and you are welcome to redistribute it
668 | under certain conditions; type `show c' for details.
669 |
670 | The hypothetical commands `show w' and `show c' should show the appropriate
671 | parts of the General Public License. Of course, your program's commands
672 | might be different; for a GUI interface, you would use an "about box".
673 |
674 | You should also get your employer (if you work as a programmer) or school,
675 | if any, to sign a "copyright disclaimer" for the program, if necessary.
676 | For more information on this, and how to apply and follow the GNU GPL, see
677 | .
678 |
679 | The GNU General Public License does not permit incorporating your program
680 | into proprietary programs. If your program is a subroutine library, you
681 | may consider it more useful to permit linking proprietary applications with
682 | the library. If this is what you want to do, use the GNU Lesser General
683 | Public License instead of this License. But first, please read
684 | .
685 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | BUILD:=bin
2 | SRC:=$(shell find src | grep -e "\.c")
3 | OBJ:=$(patsubst src/%.c,$(BUILD)/%.o,$(SRC))
4 | LIBNAME:=$(BUILD)/libmoonshot.so
5 |
6 | all: clean $(LIBNAME)
7 |
8 | clean:
9 | rm -rf $(BUILD) moonshot
10 |
11 | moonshot: $(BUILD)/cli
12 | mv bin/cli moonshot
13 |
14 | install: moonshot
15 | cp $(LIBNAME) $(HOME)/bin
16 | gcc $(BUILD)/cli.o $(HOME)/bin/libmoonshot.so -o $(HOME)/bin/moonshot
17 |
18 | $(BUILD):
19 | mkdir $(BUILD)
20 |
21 | $(BUILD)/%.o: src/%.c $(BUILD)
22 | gcc -c -fPIC src/$*.c -o $@
23 |
24 | $(LIBNAME): $(OBJ)
25 | gcc -shared $(OBJ) -o $(LIBNAME)
26 |
27 | $(BUILD)/%: tools/%.c $(LIBNAME)
28 | gcc -c tools/$*.c -o $(BUILD)/$*.o
29 | gcc $(BUILD)/$*.o $(LIBNAME) -o $(BUILD)/$*
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Moonshot
4 | **version** 0.9.0 (beta)
5 |
6 | Moonshot is an optionally-typed object-oriented extension language for Lua. This project allows you to use your favorite Lua libraries and frameworks with a more organized and error-safe code base. Moonshot is lightweight, and doesn't weigh down on your runtime. It gives you full interop with vanilla Lua as well as a fully developed optional typing system.
7 |
8 | ## Getting Started
9 | To build the project, simply run:
10 | ```
11 | make moonshot
12 | ```
13 |
14 | and then to install it globally, run:
15 | ```
16 | make install
17 | ```
18 |
19 | ## Todo
20 | - [ ] Give AST nodes a line number for better traversal stage error messages
21 |
22 | ## Developers
23 | Moonshot was developed by [LugoCorp](http://lugocorp.net)
24 |
25 | If you encounter an error while using Moonshot, please create an issue on the [GitHub repository](https://github.com/lugocorp/moonshot).
26 |
--------------------------------------------------------------------------------
/moonshot.svg:
--------------------------------------------------------------------------------
1 |
2 |
80 |
--------------------------------------------------------------------------------
/src/entities.c:
--------------------------------------------------------------------------------
1 | #include "./internal.h"
2 | #include
3 | #include
4 | #include
5 |
6 | /*
7 | Return the number of constructors present within a single class
8 | Used in class validation procedure, because classes should only have 1 constructor
9 | */
10 | int num_constructors(ClassNode* data){
11 | int cons=0;
12 | for(int a=0;als->n;a++){
13 | AstNode* e=(AstNode*)get_from_list(data->ls,a);
14 | if(e->type==AST_FUNCTION){
15 | FunctionNode* func=(FunctionNode*)(e->data);
16 | if(func->is_constructor) cons++;
17 | }
18 | }
19 | return cons;
20 | }
21 |
22 | /*
23 | Searches a class's methods for a constructor
24 | Returns NULL if the class has no custom constructor
25 | */
26 | FunctionNode* get_constructor(ClassNode* data){
27 | for(int a=0;als->n;a++){
28 | AstNode* e=(AstNode*)get_from_list(data->ls,a);
29 | if(e->type==AST_FUNCTION){
30 | FunctionNode* func=(FunctionNode*)(e->data);
31 | if(func->is_constructor) return func;
32 | }
33 | }
34 | return NULL;
35 | }
36 |
37 | /*
38 | Returns a list of all fields given a AST_CLASS or AST_INTERFACE node
39 | The returned list is full of AstNodes
40 | */
41 | List* get_all_expected_fields(AstNode* node){
42 | List* ls=new_default_list();
43 | if(node->type==AST_CLASS){
44 | ClassNode* clas=(ClassNode*)(node->data);
45 | append_all(ls,clas->ls);
46 | for(int a=0;ainterfaces->n;a++){
47 | InterfaceNode* inter=interface_exists((char*)get_from_list(clas->interfaces,a));
48 | AstNode* node1=new_node(AST_INTERFACE,-1,inter);
49 | append_all(ls,get_all_expected_fields(node1));
50 | free(node1);
51 | }
52 | clas=class_exists(clas->parent);
53 | if(clas){
54 | AstNode* node1=new_node(AST_CLASS,-1,clas);
55 | append_all(ls,get_all_expected_fields(node1));
56 | free(node1);
57 | }
58 | }else if(node->type==AST_INTERFACE){
59 | InterfaceNode* inter=(InterfaceNode*)(node->data);
60 | while(inter){
61 | append_all(ls,inter->ls);
62 | inter=interface_exists(inter->parent);
63 | }
64 | }
65 | return ls;
66 | }
67 |
68 | /*
69 | Collects every method from a class or interface's interface ancestors
70 | Travels back in a straight path for interface nodes
71 | Travels in a branching path for class nodes
72 | */
73 | static List* get_interface_ancestor_methods(AstNode* node){
74 | char* name;
75 | List* ls=new_default_list();
76 | if(node->type==AST_CLASS){
77 | ClassNode* c=(ClassNode*)(node->data);
78 | AstNode* inode=new_node(AST_INTERFACE,-1,NULL);
79 | while(c){
80 | for(int a=0;ainterfaces->n;a++){
81 | name=(char*)get_from_list(c->interfaces,a);
82 | inode->data=interface_exists(name);
83 | if(inode->data){
84 | List* ls1=get_interface_ancestor_methods(inode);
85 | append_all(ls,ls1);
86 | dealloc_list(ls1);
87 | }
88 | }
89 | c=class_exists(c->parent);
90 | }
91 | free(inode);
92 | }else if(node->type==AST_INTERFACE){
93 | InterfaceNode* i=(InterfaceNode*)(node->data);
94 | while(i){
95 | for(int a=0;als->n;a++) add_to_list(ls,((AstNode*)get_from_list(i->ls,a))->data);
96 | i=interface_exists(i->parent);
97 | }
98 | }
99 | return ls;
100 | }
101 |
102 | /*
103 | Collects every method from a class and its class ancestors
104 | Just goes back through parent classes in a straight path
105 | */
106 | static List* get_class_ancestor_methods(ClassNode* node){
107 | List* ls=new_default_list();
108 | while(node){
109 | for(int a=0;als->n;a++){
110 | AstNode* e=(AstNode*)get_from_list(node->ls,a);
111 | if(e->type==AST_FUNCTION) add_to_list(ls,e->data);
112 | }
113 | node=class_exists(node->parent);
114 | }
115 | return ls;
116 | }
117 |
118 | /*
119 | Retrieves all the ancestor methods from a class's ancestor classes and interfaces
120 | Then subtracts the two lists, returning any missing implementations in a List
121 | */
122 | List* get_missing_class_methods(ClassNode* c){
123 | AstNode* node=new_node(AST_CLASS,-1,c);
124 | List* missing=get_interface_ancestor_methods(node);
125 | List* found=get_class_ancestor_methods(c);
126 | free(node);
127 | int a=0;
128 | while(an){
129 | int removed=0;
130 | for(int b=0;bn;b++){
131 | FunctionNode* f1=(FunctionNode*)get_from_list(missing,a);
132 | FunctionNode* f2=(FunctionNode*)get_from_list(found,b);
133 | if(methods_equivalent(f1,f2)){
134 | remove_from_list(missing,a);
135 | removed=1;
136 | break;
137 | }
138 | }
139 | if(!removed) a++;
140 | }
141 | dealloc_list(found);
142 | return missing;
143 | }
144 |
145 | /*
146 | Returns 1 if the two functions have the same signature (name and type)
147 | Helpful for overriding or implementing methods from ancestors
148 | */
149 | int methods_equivalent(FunctionNode* f1,FunctionNode* f2){
150 | if(!f1->name || !f2->name) return 0;
151 | assert(f1->name->type==AST_ID); // Assumes the two methods belong to classes (name nodes are of type AST_ID)
152 | assert(f2->name->type==AST_ID); // Assumes the two methods belong to classes (name nodes are of type AST_ID)
153 | AstNode* node=new_node(AST_FUNCTION,-1,f1);
154 | AstNode* type1=get_type(node);
155 | free(node);
156 | node=new_node(AST_FUNCTION,-1,f2);
157 | AstNode* type2=get_type(node);
158 | free(node);
159 | return !strcmp((char*)(f1->name->data),(char*)(f2->name->data)) && typed_match(type1,type2);
160 | }
161 |
162 | /*
163 | Returns a List containing all the fields or a class and all its ancestors
164 | The youngest subclasses' methods are first in the List
165 | */
166 | List* get_all_class_fields(ClassNode* data){
167 | List* ls=new_default_list();
168 | while(data){
169 | append_all(ls,data->ls);
170 | data=class_exists(data->parent);
171 | }
172 | return ls;
173 | }
174 |
175 | /*
176 | Calculates subclass fields by flattening ancestor fields into a Map
177 | ls is a list of ancestor fields (pass result of get_all_class_fields)
178 | Returns NULL if multiple fields share the same name but different types
179 | */
180 | Map* collapse_ancestor_class_fields(List* ls){
181 | Map* m=new_default_map();
182 | for(int a=0;an;a++){
183 | AstNode* node=(AstNode*)get_from_list(ls,a);
184 | char* name=NULL;
185 | if(node->type==AST_DEFINE) name=((BinaryNode*)(node->data))->text;
186 | if(node->type==AST_FUNCTION){
187 | FunctionNode* data=(FunctionNode*)(node->data);
188 | if(!data->name) continue;
189 | assert(data->name->type==AST_ID); // Assumes the function's name is AST_ID
190 | name=(char*)(data->name->data);
191 | }
192 | AstNode* e=(AstNode*)get_from_map(m,name);
193 | if(e){
194 | AstNode* rtype=get_type(e);
195 | AstNode* ltype=get_type(node);
196 | if(node->type!=e->type || !typed_match(ltype,rtype)){
197 | dealloc_map(m);
198 | return NULL;
199 | }
200 | }else{
201 | put_in_map(m,name,node);
202 | }
203 | }
204 | return m;
205 | }
206 |
207 | /*
208 | Grabs the FunctionNode that corresponds to the child class's function
209 | clas should be the parent of the class who has the function method
210 | */
211 | FunctionNode* get_parent_method(ClassNode* clas,FunctionNode* method){
212 | while(clas){
213 | for(int a=0;als->n;a++){
214 | AstNode* e=(AstNode*)get_from_list(clas->ls,a);
215 | if(e->type!=AST_FUNCTION) continue;
216 | FunctionNode* func=(FunctionNode*)(e->data);
217 | if(method->is_constructor){
218 | if(func->is_constructor) return func;
219 | }else if(func->is_constructor){
220 | continue;
221 | }else{
222 | assert(method->name->type==AST_ID); // I'm assuming both method->name and func->name are AST_ID types
223 | assert(func->name->type==AST_ID); // I'm assuming both method->name and func->name are AST_ID types
224 | if(strcmp((char*)(method->name->data),(char*)(func->name->data))) continue;
225 | AstNode* func_type=get_type(e);
226 | AstNode* m=new_node(AST_FUNCTION,-1,method);
227 | AstNode* method_type=get_type(m);
228 | free(m);
229 | if(typed_match(func_type,method_type)){
230 | return func;
231 | }
232 | }
233 | }
234 | clas=class_exists(clas->parent);
235 | }
236 | return NULL;
237 | }
238 |
--------------------------------------------------------------------------------
/src/internal.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #define PRIMITIVE_STRING "string"
4 | #define PRIMITIVE_FLOAT "float"
5 | #define PRIMITIVE_BOOL "bool"
6 | #define PRIMITIVE_INT "int"
7 | #define PRIMITIVE_NIL "nil"
8 |
9 | /*
10 | List: a dynamic-length array
11 | */
12 | typedef struct{
13 | void** items;
14 | int max;
15 | int n;
16 | } List;
17 |
18 | List* new_list(int max);
19 | List* new_default_list();
20 | void* get_from_list(List* ls,int i);
21 | void* remove_from_list(List* ls,int i);
22 | void append_all(List* ls,List* ls1);
23 | int add_to_list(List* ls,void* e);
24 | void dealloc_list(List* ls);
25 |
26 | /*
27 | Map: a key-value object
28 | */
29 | typedef struct{
30 | char* k;
31 | void* v;
32 | } Pair;
33 | typedef struct{
34 | Pair* data;
35 | int max;
36 | int n;
37 | } Map;
38 | Map* new_map(int max);
39 | Map* new_default_map();
40 | void* get_from_map(Map* m,char* k);
41 | void* iterate_from_map(Map* m,int i);
42 | void put_in_map(Map* m,char* k,void* v);
43 | void dealloc_map(Map* m);
44 |
45 | /*
46 | Token: a symbol from the input code utilized by the parser
47 | */
48 | typedef struct{
49 | char* text;
50 | int type;
51 | int line;
52 | } Token;
53 |
54 | void deallocate_token(Token* token);
55 |
56 | // AST node types
57 | typedef struct{
58 | void* data;
59 | int type;
60 | int line;
61 | } AstNode;
62 |
63 | typedef struct{
64 | AstNode* node;
65 | List* list;
66 | } AstListNode;
67 |
68 | typedef struct{
69 | int is_constructor; // 1 if the function is a constructor
70 | AstNode* functype; // Overall function type
71 | AstNode* name; // An AST_LHS or AST_ID node representing the name, or NULL for constructors
72 | AstNode* type; // Return type of the function (part of functype)
73 | List* body; // List of AstNodes for the function body
74 | List* args; // List of StringAstNodes for function parameters
75 | } FunctionNode;
76 |
77 | typedef struct{
78 | List* keys; // List of strings
79 | List* vals; // List of AstNodes
80 | } TableNode;
81 |
82 | typedef struct{
83 | AstNode* l;
84 | AstNode* r;
85 | } AstAstNode;
86 |
87 | typedef struct{
88 | AstNode* node;
89 | char* text;
90 | } StringAstNode;
91 |
92 | typedef struct{
93 | AstNode* num1;
94 | AstNode* num2;
95 | AstNode* num3;
96 | char* name;
97 | List* body;
98 | } FornumNode;
99 |
100 | typedef struct{
101 | AstNode* lhs;
102 | AstNode* tuple;
103 | List* body;
104 | } ForinNode;
105 |
106 | typedef struct{
107 | AstNode* l;
108 | AstNode* r;
109 | char* text;
110 | } BinaryNode;
111 |
112 | typedef struct{
113 | AstNode* type; // Type representing the interface itself
114 | char* parent; // Name of parent interface, or NULL if there is none
115 | char* name; // Name of interface
116 | List* ls; // List of AstNodes (AST_FUNCTION nodes)
117 | } InterfaceNode;
118 |
119 | typedef struct{
120 | List* interfaces; // List of strings
121 | AstNode* type; // Type representing the class itself
122 | char* parent; // Name of parent class, or NULL if there is none
123 | char* name; // Name of class
124 | List* ls; // List of AstNodes
125 | } ClassNode;
126 |
127 | typedef struct{
128 | AstNode* expr;
129 | AstNode* next;
130 | List* body;
131 | } IfNode;
132 |
133 | // Traversal algorithm structs
134 | typedef struct{
135 | AstNode* type; // Type that the registered type is equivalent to
136 | int relation; // Type equivalence type (check enum Relations)
137 | char* name; // Name of the registered type
138 | int scope; // The index of the scope where this equivalence was defined
139 | } EqualTypesNode;
140 |
141 | typedef struct{
142 | List* interfaces_registry; // List of InterfaceNodes
143 | List* functions_registry; // List of FunctionNodes
144 | List* classes_registry; // List of ClassNodes
145 | List* types_registry; // List of strings
146 | List* defs; // List of StringAstNodes representing local definitions
147 | void* data; // Context node attached to this scope
148 | int type; // The type of this scope
149 | } Scope;
150 |
151 | // File requirements
152 | typedef struct{
153 | char* filename; // Filename of the required file
154 | AstNode* tree; // Parsed AST tree
155 | List* tokens; // Token list for file
156 | int completed; // The highest step completed on this file
157 | } Require;
158 |
159 | // Enum for all traversal steps
160 | enum STEPS{
161 | STEP_TYPEDEF, // Step for processing type definitions, runs for each scope
162 | STEP_RELATE, // Step for processing type relations, runs after typedef step for each scope
163 | STEP_CHECK, // General validation step, runs after relate step for each scope
164 | STEP_OUTPUT // Post-validation step for outputting Lua code, runs once after all validation
165 | };
166 |
167 | // Enum for all scope types
168 | enum SCOPE_TYPES{
169 | SCOPE_FUNCTION, SCOPE_CLASS, SCOPE_NONE
170 | };
171 |
172 | // Enum for all equivalent type relationships
173 | enum RELATIONS{
174 | RL_EXTENDS, RL_EQUALS, RL_IMPLEMENTS
175 | };
176 |
177 | // Enum for all possible tokens
178 | enum TOKENS{
179 |
180 | // Lua reserved keywords (starts with 0)
181 | TK_AND, TK_BREAK,
182 | TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
183 | TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
184 | TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
185 |
186 | // Lua other terminal symbols (starts with 22)
187 | TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
188 | TK_SHL, TK_SHR,
189 | TK_DBCOLON, TK_EOS,
190 | TK_FLT, TK_INT, TK_NAME, TK_STRING,
191 |
192 | // New tokens for vanilla lexing (starts with 37)
193 | TK_PAREN, TK_CURLY, TK_SQUARE,
194 | TK_QUOTE, TK_REQUIRE,
195 | TK_UNARY, TK_BINARY,
196 | TK_SPACE, TK_MISC,
197 |
198 | // New tokens specific to Moonshot
199 | TK_NEW, TK_FINAL, TK_TYPEDEF, TK_VAR,
200 | TK_INTERFACE, TK_CLASS, TK_EXTENDS, TK_IMPLEMENTS,
201 | TK_WHERE, TK_CONSTRUCTOR, TK_SUPER
202 |
203 | };
204 |
205 | // Enum for all grammar rules
206 |
207 | enum RULES{
208 | // Node's data is NULL
209 | AST_NONE, AST_BREAK, AST_TYPE_ANY, AST_TYPE_VARARG,
210 |
211 | // Node's data is char*
212 | AST_LABEL, AST_GOTO, AST_ID, AST_TYPE_BASIC,
213 |
214 | // Node's data is List*
215 | AST_STMT, AST_DO, AST_LTUPLE, AST_TYPE_TUPLE, AST_ELSE,
216 |
217 | // Node's data is AstListNode*
218 | AST_REPEAT, AST_WHILE, AST_TYPE_FUNC, AST_TUPLE,
219 |
220 | // Node's data is ClassNode*
221 | AST_CLASS,
222 |
223 | // Node's data is InterfaceNode*
224 | AST_INTERFACE,
225 |
226 | // Node's data is FunctionNode*
227 | AST_FUNCTION,
228 |
229 | // Node's data is TableNode*
230 | AST_TABLE,
231 |
232 | // Node's data is AstAstNode*
233 | AST_SET, AST_CALL, AST_SUB,
234 |
235 | // Node's data is Binary node
236 | AST_BINARY, AST_UNARY, AST_DEFINE,
237 |
238 | // Node's data is AstNode*
239 | AST_RETURN, AST_PAREN, AST_REQUIRE, AST_SUPER, AST_LIST,
240 |
241 | // Node's data is StringAstNode*
242 | AST_FIELD, AST_LOCAL, AST_TYPEDEF, AST_PRIMITIVE,
243 |
244 | // Node's data is FornumNode*
245 | AST_FORNUM,
246 |
247 | // Node's data is ForinNode*
248 | AST_FORIN, AST_ELSEIF, AST_IF,
249 |
250 | // Node's data is something else
251 | AST_UNKNOWN
252 | };
253 |
254 | // Implemented in moonshot.c
255 | void add_error_internal(int line,const char* msg,va_list args);
256 | char* format_string(int indent,const char* msg,va_list args);
257 | void add_error(int line,const char* msg,...);
258 | int require_file(char* filename,int step);
259 | char* collapse_string_list(List* ls);
260 | void dealloc_token_buffer(List* ls);
261 | char* strip_quotes(char* str);
262 | char* copy_string(char* str);
263 | char* string_from_int(int a);
264 |
265 | // Implemented in tokenizer.c
266 | void dealloc_token(Token* tk);
267 | List* tokenize(FILE* f);
268 |
269 | // Implemented in parser.c
270 | AstNode* parse(List* ls);
271 | AstNode* parse_function(AstNode* type,int include_body);
272 | AstNode* parse_constructor(char* classname);
273 | AstNode* parse_paren_or_tuple_function();
274 | AstNode* parse_potential_tuple_lhs();
275 | AstNode* parse_define(AstNode* type);
276 | AstNode* parse_function_or_define();
277 | AstNode* parse_call(AstNode* lhs);
278 | AstNode* parse_table_or_list();
279 | AstNode* parse_set_or_call();
280 | AstNode* parse_interface();
281 | AstNode* parse_typedef();
282 | AstNode* parse_require();
283 | AstNode* parse_repeat();
284 | AstNode* parse_string();
285 | AstNode* parse_number();
286 | AstNode* parse_return();
287 | AstNode* parse_fornum();
288 | AstNode* parse_elseif();
289 | AstNode* parse_super();
290 | AstNode* parse_tuple();
291 | AstNode* parse_while();
292 | AstNode* parse_local();
293 | AstNode* parse_table();
294 | AstNode* parse_forin();
295 | AstNode* parse_label();
296 | AstNode* parse_break();
297 | AstNode* parse_class();
298 | AstNode* parse_list();
299 | AstNode* parse_type();
300 | AstNode* parse_stmt();
301 | AstNode* parse_else();
302 | AstNode* parse_list();
303 | AstNode* parse_goto();
304 | AstNode* parse_expr();
305 | AstNode* parse_lhs();
306 | AstNode* parse_if();
307 | AstNode* parse_do();
308 |
309 | // Implemented in nodes.c
310 | FornumNode* new_fornum_node(char* name,AstNode* num1,AstNode* num2,AstNode* num3,List* body);
311 | EqualTypesNode* new_equal_types_node(char* name,AstNode* type,int relation,int scope);
312 | FunctionNode* new_function_node(AstNode* name,AstNode* type,List* args,List* body);
313 | ClassNode* new_class_node(char* name,char* parent,List* interfaces,List* ls);
314 | InterfaceNode* new_interface_node(char* name,char* parent,List* ls);
315 | ForinNode* new_forin_node(AstNode* lhs,AstNode* tuple,List* body);
316 | StringAstNode* new_primitive_node(char* text,const char* type);
317 | BinaryNode* new_binary_node(char* text,AstNode* l,AstNode* r);
318 | StringAstNode* new_string_ast_node(char* text,AstNode* ast);
319 | IfNode* new_if_node(AstNode* expr,AstNode* next,List* body);
320 | AstListNode* new_ast_list_node(AstNode* ast,List* list);
321 | AstAstNode* new_ast_ast_node(AstNode* l,AstNode* r);
322 | TableNode* new_table_node(List* keys,List* vals);
323 | BinaryNode* new_unary_node(char* op,AstNode* e);
324 | AstNode* new_node(int type,int line,void* data);
325 | void dealloc_ast_type(AstNode* node);
326 | void dealloc_ast_node(AstNode* node);
327 |
328 | /*
329 | * The parsing step should not have
330 | * access to these functions or it may
331 | * cause a segmentation fault.
332 | */
333 | #ifndef MOONSHOT_PARSING
334 |
335 | // Implemented in scopes.c
336 | void push_function_scope(FunctionNode* node);
337 | void register_interface(InterfaceNode* node);
338 | InterfaceNode* interface_exists(char* name);
339 | void register_function(FunctionNode* node);
340 | StringAstNode* get_scoped_var(char* name);
341 | FunctionNode* function_exists(char* name);
342 | void register_primitive(const char* name);
343 | int add_scoped_var(StringAstNode* node);
344 | int field_defined_in_class(char* name);
345 | void push_class_scope(ClassNode* node);
346 | void register_class(ClassNode* node);
347 | ClassNode* class_exists(char* name);
348 | FunctionNode* get_function_scope();
349 | FunctionNode* get_method_scope();
350 | void register_type(char* name);
351 | ClassNode* get_class_scope();
352 | int type_exists(char* name);
353 | void preempt_scopes();
354 | void dealloc_scopes();
355 | int get_num_scopes();
356 | Scope* get_scope();
357 | void init_scopes();
358 | void push_scope();
359 | void pop_scope();
360 |
361 | // Implemented in types.c
362 | int add_type_equivalence(char* name,AstNode* type,int relation);
363 | int add_child_type(char* child,char* parent,int relation);
364 | void quell_expired_scope_equivalences(int scope);
365 | int is_primitive(AstNode* node,const char* type);
366 | int types_equivalent(char* name,AstNode* type);
367 | int compound_type_exists(AstNode* node);
368 | List* get_equivalent_types(char* name);
369 | int typed_match(AstNode* l,AstNode* r);
370 | int is_variadic_function(List* args);
371 | char* stringify_type(AstNode* node);
372 | AstNode* get_type(AstNode* node);
373 | char* base_type(char* name);
374 | void print_types_graph();
375 | void dealloc_types();
376 | void init_types();
377 |
378 | // Implemented in entities.c
379 | FunctionNode* get_parent_method(ClassNode* clas,FunctionNode* method);
380 | int methods_equivalent(FunctionNode* f1,FunctionNode* f2);
381 | List* get_missing_class_methods(ClassNode* node);
382 | FunctionNode* get_constructor(ClassNode* data);
383 | Map* collapse_ancestor_class_fields(List* ls);
384 | List* get_all_expected_fields(AstNode* node);
385 | List* get_all_class_fields(ClassNode* data);
386 | int num_constructors(ClassNode* data);
387 |
388 | // Implemented in traversal.c
389 | void traverse(AstNode* node,int step);
390 | void dealloc_traverse();
391 | void init_traverse();
392 | int get_num_indents();
393 | AstNode* any_type_const();
394 | AstNode* int_type_const();
395 | AstNode* bool_type_const();
396 | AstNode* float_type_const();
397 | void set_output(FILE* output);
398 | void process_node_list(List* ls);
399 | void process_list_primitive_node(AstNode* node);
400 | void process_interface(AstNode* node);
401 | void process_primitive(AstNode* node);
402 | void process_function(AstNode* node);
403 | void process_require(AstNode* node);
404 | void process_typedef(AstNode* node);
405 | void process_repeat(AstNode* node);
406 | void process_ltuple(AstNode* node);
407 | void process_return(AstNode* node);
408 | void process_binary(AstNode* node);
409 | void process_fornum(AstNode* node);
410 | void process_elseif(AstNode* node);
411 | void process_define(AstNode* node);
412 | void process_class(AstNode* node);
413 | void process_super(AstNode* node);
414 | void process_break(AstNode* node);
415 | void process_paren(AstNode* node);
416 | void process_forin(AstNode* node);
417 | void process_unary(AstNode* node);
418 | void process_tuple(AstNode* node);
419 | void process_table(AstNode* node);
420 | void process_local(AstNode* node);
421 | void process_while(AstNode* node);
422 | void process_field(AstNode* node);
423 | void process_label(AstNode* node);
424 | void process_node(AstNode* node);
425 | void process_goto(AstNode* node);
426 | void process_call(AstNode* node);
427 | void process_else(AstNode* node);
428 | void process_set(AstNode* node);
429 | void process_sub(AstNode* node);
430 | void process_if(AstNode* node);
431 | void process_do(AstNode* node);
432 | void process_id(AstNode* node);
433 |
434 | #endif
435 |
--------------------------------------------------------------------------------
/src/list.c:
--------------------------------------------------------------------------------
1 | #include "./internal.h"
2 | #include
3 | #include
4 | #include
5 |
6 | /*
7 | Instantiates a new List object with some initial max capacity
8 | */
9 | List* new_list(int max){
10 | void** items=(void**)malloc(max*sizeof(void*));
11 | List* ls=(List*)malloc(sizeof(List));
12 | ls->items=items;
13 | ls->max=max;
14 | ls->n=0;
15 | return ls;
16 | }
17 |
18 | /*
19 | Instantiates a List with the default initial max capacity
20 | */
21 | List* new_default_list(){
22 | return new_list(10);
23 | }
24 |
25 | /*
26 | Gets the i-th item from a list
27 | returns null if i is out of range
28 | */
29 | void* get_from_list(List* ls,int i){
30 | assert(in && i>=0); // Safety check
31 | return ls->items[i];
32 | }
33 |
34 | void* remove_from_list(List* ls,int i){
35 | assert(in && i>=0); // Safety check
36 | void* e=get_from_list(ls,i);
37 | for(int a=i+1;an;a++) ls->items[a-1]=ls->items[a];
38 | ls->items[--(ls->n)]=NULL;
39 | return e;
40 | }
41 |
42 | /*
43 | Appends an item to a list
44 | Doubles the list's capacity if it's already full
45 | */
46 | int add_to_list(List* ls,void* e){
47 | if(ls->n==ls->max){
48 | void** items=(void**)malloc(ls->max*2*sizeof(void*));
49 | memcpy(items,ls->items,ls->max*sizeof(void*));
50 | free(ls->items);
51 | ls->items=items;
52 | ls->max*=2;
53 | }
54 | ls->items[ls->n++]=e;
55 | }
56 |
57 | /*
58 | Appends every element from ls1 to ls
59 | */
60 | void append_all(List* ls,List* ls1){
61 | for(int a=0;an;a++){
62 | add_to_list(ls,get_from_list(ls1,a));
63 | }
64 | }
65 |
66 | /*
67 | Deallocates a list object
68 | Does not touch the list's contents
69 | */
70 | void dealloc_list(List* ls){
71 | free(ls->items);
72 | free(ls);
73 | }
74 |
--------------------------------------------------------------------------------
/src/map.c:
--------------------------------------------------------------------------------
1 | #include "./internal.h"
2 | #include
3 | #include
4 | #include
5 |
6 | /*
7 | Instantiates a new Map object with some initial max capacity
8 | */
9 | Map* new_map(int max){
10 | Pair* items=(Pair*)malloc(max*sizeof(Pair));
11 | Map* m=(Map*)malloc(sizeof(Map));
12 | m->data=items;
13 | m->max=max;
14 | m->n=0;
15 | return m;
16 | }
17 |
18 | /*
19 | Instantiates a Map with the default initial max capacity
20 | */
21 | Map* new_default_map(){
22 | return new_map(10);
23 | }
24 |
25 | /*
26 | Returns a value associated with some key from a map
27 | */
28 | void* get_from_map(Map* m,char* k){
29 | for(int a=0;an;a++){
30 | Pair p=m->data[a];
31 | if(!strcmp(p.k,k)) return p.v;
32 | }
33 | return NULL;
34 | }
35 |
36 | /*
37 | Returns a value at arbitrary position i within a map
38 | Used in traversal algorithms
39 | */
40 | void* iterate_from_map(Map* m,int i){
41 | assert(in && i>=0); // Safety check
42 | return (m->data[i]).v;
43 | }
44 |
45 | /*
46 | Puts a key-value pair in a map
47 | Doubles the max length of the map if it's already full
48 | Replaces the value associates with key k if it already exists
49 | */
50 | void put_in_map(Map* m,char* k,void* v){
51 | for(int a=0;an;a++){
52 | Pair p=m->data[a];
53 | if(!strcmp(p.k,k)){
54 | (m->data[a]).v=v;
55 | return;
56 | }
57 | }
58 | if(m->n==m->max){
59 | m->max*=2;
60 | Pair* tmp=(Pair*)malloc(sizeof(Pair)*m->max);
61 | for(int a=0;an;a++) tmp[a]=m->data[a];
62 | free(m->data);
63 | m->data=tmp;
64 | }
65 | m->data[m->n].k=k;
66 | m->data[m->n].v=v;
67 | m->n++;
68 | }
69 |
70 | /*
71 | Deallocates a map
72 | Does not touch the map's contents
73 | */
74 | void dealloc_map(Map* m){
75 | free(m->data);
76 | free(m);
77 | }
78 |
--------------------------------------------------------------------------------
/src/moonshot.c:
--------------------------------------------------------------------------------
1 | #include "./moonshot.h"
2 | #include "./internal.h"
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #define ERROR_BUFFER_LENGTH 256 // Maximum length for an error message
9 | static int line_written; // Zero if there's no content on the current output line yet
10 | static List* srcs; // Stack of files you're parsing/traversing
11 | static List* requires; // List of required files
12 | static List* errors; // List of error strings
13 | static int error_i; // Index of currently consumed error
14 | static FILE* _input; // Input for source code
15 |
16 | /*
17 | Return the number of compilation errors
18 | */
19 | int moonshot_num_errors(){
20 | return errors->n;
21 | }
22 |
23 | /*
24 | Returns the next error message from compilation
25 | Returns NULL if there's no more errors
26 | */
27 | char* moonshot_next_error(){
28 | if(errors && error_in) return (char*)get_from_list(errors,error_i++);
29 | return NULL;
30 | }
31 |
32 | /*
33 | Custom string format function
34 | */
35 | char* format_string(int indent,const char* msg,va_list args){
36 | List* ls=new_default_list();
37 | char symbol[2]={0,0};
38 | int n=strlen(msg);
39 | for(int a=0;an;a++) free(get_from_list(ls,a));
79 | free(ls);
80 | return str;
81 | }
82 |
83 | /*
84 | Adds an error into the compiler error stream
85 | Must include at least one parameter after msg or you'll get an error
86 | Exits with a special error if your msg and va_args cause the error buffer to overflow
87 | */
88 | void add_error(int line,const char* msg,...){
89 | va_list args;
90 | va_start(args,msg);
91 | add_error_internal(line,msg,args);
92 | va_end(args);
93 | }
94 | void add_error_internal(int line,const char* msg,va_list args){
95 | List* ls=new_default_list();
96 | add_to_list(ls,format_string(0,msg,args));
97 | if(srcs->n){
98 | char* file=(char*)get_from_list(srcs,srcs->n-1);
99 | char* suffix=(char*)malloc(sizeof(char)*(strlen(file)+5));
100 | sprintf(suffix," in %s",file);
101 | add_to_list(ls,suffix);
102 | }
103 | if(line>=0){
104 | char* str=string_from_int(line);
105 | char* suffix=(char*)malloc(sizeof(char)*(strlen(str)+9));
106 | sprintf(suffix," (line %i)",line);
107 | add_to_list(ls,suffix);
108 | }
109 | char* err=collapse_string_list(ls);
110 | for(int a=0;an;a++) free(get_from_list(ls,a));
111 | free(ls);
112 | add_to_list(errors,err);
113 | }
114 |
115 | /*
116 | Deallocates all tokens within the token list and the list itself
117 | */
118 | void dealloc_token_buffer(List* ls){
119 | for(int a=0;an;a++) dealloc_token((Token*)get_from_list(ls,a));
120 | dealloc_list(ls);
121 | }
122 |
123 | /*
124 | Deallocates all error strings in the errors list and the list itself
125 | */
126 | static void dealloc_errors(){
127 | for(int a=0;an;a++) free(get_from_list(errors,a));
128 | dealloc_list(errors);
129 | errors=NULL;
130 | }
131 |
132 | /*
133 | Takes a List of strings and collapses it into one single string
134 | */
135 | char* collapse_string_list(List* ls){
136 | int l=0;
137 | for(int a=0;an;a++) l+=strlen((char*)get_from_list(ls,a));
138 | char* copy=(char*)malloc(sizeof(char)*(l+1));
139 | copy[0]=0;
140 | for(int a=0;an;a++) strcat(copy,(char*)get_from_list(ls,a));
141 | return copy;
142 | }
143 |
144 | /*
145 | Copies a string but without the first and last characters (quotes)
146 | */
147 | char* strip_quotes(char* str){
148 | int l=strlen(str);
149 | char* copy=(char*)malloc(sizeof(char)*(l-1));
150 | strncpy(copy,str+1,l-2);
151 | copy[l-2]=0;
152 | return copy;
153 | }
154 |
155 | /*
156 | Copies a string
157 | */
158 | char* copy_string(char* str){
159 | int l=strlen(str);
160 | char* copy=(char*)malloc(sizeof(char)*(l+1));
161 | strcpy(copy,str);
162 | return copy;
163 | }
164 |
165 | /*
166 | Get string from int
167 | */
168 | char* string_from_int(int a){
169 | int n=(a/10)+1;
170 | if(n<0) n++;
171 | char* msg=(char*)malloc(sizeof(char)*(n+1));
172 | sprintf(msg,"%i",a);
173 | return msg;
174 | }
175 |
176 | /*
177 | Initializes this module
178 | */
179 | void init_requires(){
180 | requires=new_default_list();
181 | srcs=new_default_list();
182 | }
183 |
184 | /*
185 | Deallocates a list of required files
186 | */
187 | static void dealloc_requires(){
188 | for(int a=requires->n-1;a>=0;a--){
189 | Require* r=(Require*)get_from_list(requires,a);
190 | if(r->tree) dealloc_ast_node(r->tree);
191 | if(r->tokens) dealloc_token_buffer(r->tokens);
192 | free(r->filename);
193 | free(r);
194 | }
195 | dealloc_list(requires);
196 | dealloc_list(srcs);
197 | requires=NULL;
198 | srcs=NULL;
199 | }
200 |
201 | /*
202 | Manually adds a dummy node for the given filename
203 | */
204 | void dummy_required_file(char* filename){
205 | char* copy=copy_string(filename);
206 | if(srcs->n){
207 | remove_from_list(srcs,srcs->n-1);
208 | }
209 | Require* r=(Require*)malloc(sizeof(Require));
210 | r->completed=STEP_OUTPUT;
211 | r->filename=copy;
212 | r->tokens=NULL;
213 | r->tree=NULL;
214 | add_to_list(requires,r);
215 | add_to_list(srcs,copy);
216 | }
217 |
218 | /*
219 | Tokenizes, parses and traverses another file to import external Moon types
220 | Will only bother if the filename ends in .moon (is Moonshot source code)
221 | Also checks to ensure that we're not processing a file we've already processed
222 | Returns 1 if the required file is a Moonshot source file
223 | */
224 | int require_file(char* filename,int step){
225 | char* copy=strip_quotes(filename);
226 | int l=strlen(copy);
227 | if(l<5 || strcmp(copy+l-5,".moon")){
228 | free(copy);
229 | return 0;
230 | }
231 | for(int a=0;an;a++){
232 | Require* r=(Require*)get_from_list(requires,a);
233 | if(!strcmp(r->filename,copy)){
234 | if(r->completedcompleted=step;
236 | }else{
237 | free(copy);
238 | return 1;
239 | }
240 | }
241 | }
242 | add_to_list(srcs,copy);
243 | if(step==STEP_TYPEDEF){
244 | FILE* f=fopen(copy,"r");
245 | if(!f){
246 | add_error(-1,"cannot open file %s",copy);
247 | remove_from_list(srcs,srcs->n-1);
248 | free(copy);
249 | return 1;
250 | }
251 | List* ls=tokenize(f);
252 | fclose(f);
253 | if(!ls){
254 | add_error(-1,"tokenization buffer overflow",NULL);
255 | remove_from_list(srcs,srcs->n-1);
256 | free(copy);
257 | return 1;
258 | }
259 | AstNode* root=parse(ls);
260 | if(!root){
261 | remove_from_list(srcs,srcs->n-1);
262 | dealloc_token_buffer(ls);
263 | free(copy);
264 | return 1;
265 | }
266 | Require* r=(Require*)malloc(sizeof(Require));
267 | r->filename=copy;
268 | r->completed=0;
269 | r->tokens=ls;
270 | r->tree=root;
271 | add_to_list(requires,r);
272 | }
273 | for(int a=0;an;a++){
274 | Require* r=(Require*)get_from_list(requires,a);
275 | if(!strcmp(r->filename,copy) && (step!=STEP_OUTPUT || r->completedcompleted=STEP_OUTPUT;
277 | if(r->tree){
278 | assert(r->tree->type==AST_STMT);
279 | List* ls=(List*)(r->tree->data);
280 | for(int b=0;bn;b++){
281 | process_node((AstNode*)get_from_list(ls,b));
282 | }
283 | }
284 | break;
285 | }
286 | }
287 | if(step!=STEP_TYPEDEF) free(copy);
288 | remove_from_list(srcs,srcs->n-1);
289 | return 1;
290 | }
291 |
292 | /*
293 | Initializes data used by the Moonshot library
294 | */
295 | void moonshot_init(){
296 | line_written=0;
297 | requires=NULL;
298 | errors=NULL;
299 | _input=NULL;
300 | srcs=NULL;
301 | error_i=0;
302 | }
303 |
304 | /*
305 | Deallocate remaining memory from Moonshot's compilation process
306 | */
307 | void moonshot_destroy(){
308 | if(errors) dealloc_errors();
309 | }
310 |
311 | /*
312 | Sets configuration for compilation
313 | Sets source code and output I/O
314 | Also controls whether or not to write any output
315 | */
316 | void moonshot_configure(FILE* input,FILE* output){
317 | set_output(output);
318 | _input=input;
319 | }
320 |
321 | /*
322 | Read from your configured input and compile Moonshot code
323 | Will only write Lua code to output if it's set in the configuration
324 | */
325 | int moonshot_compile(){
326 | if(!requires) init_requires();
327 | if(errors) dealloc_errors();
328 | errors=new_default_list();
329 |
330 | // Tokenize
331 | List* ls=tokenize(_input);
332 | if(!ls){
333 | add_error(-1,"tokenization buffer overflow",NULL);
334 | return 0;
335 | }
336 |
337 | // Parse tokens
338 | AstNode* root=parse(ls);
339 | if(!root){
340 | dealloc_token_buffer(ls);
341 | return 0;
342 | }
343 |
344 | // AST traversal
345 | init_traverse();
346 | traverse(root,STEP_CHECK);
347 | if(!errors->n) traverse(root,STEP_OUTPUT);
348 | dealloc_traverse();
349 | dealloc_requires();
350 | dealloc_ast_node(root);
351 | dealloc_token_buffer(ls);
352 | return (errors->n)?0:1;
353 | }
354 |
--------------------------------------------------------------------------------
/src/moonshot.h:
--------------------------------------------------------------------------------
1 | #include
2 | #define VERSION "0.9.0 (beta)"
3 |
4 | void moonshot_configure(FILE* input,FILE* output);
5 | void dummy_required_file(char* filename);
6 | char* moonshot_next_error();
7 | int moonshot_num_errors();
8 | void moonshot_destroy();
9 | int moonshot_compile();
10 | void moonshot_init();
11 | void init_requires();
12 |
--------------------------------------------------------------------------------
/src/nodes.c:
--------------------------------------------------------------------------------
1 | #include "./internal.h"
2 | #include
3 | #include
4 | #include
5 |
6 | /*
7 | Deallocates an AstNode with type AST_TYPE_*
8 | */
9 | void dealloc_ast_type(AstNode* node){
10 | if(node->type==AST_TYPE_FUNC){
11 | AstListNode* data=(AstListNode*)(node->data);
12 | if(data->node) dealloc_ast_type(data->node);
13 | for(int a=0;alist->n;a++){
14 | AstNode* e=(AstNode*)get_from_list(data->list,a);
15 | dealloc_ast_type(e);
16 | }
17 | dealloc_list(data->list);
18 | free(data);
19 | }
20 | if(node->type==AST_TYPE_TUPLE){
21 | List* ls=(List*)(node->data);
22 | for(int a=0;an;a++){
23 | AstNode* e=(AstNode*)get_from_list(ls,a);
24 | dealloc_ast_type(e);
25 | }
26 | dealloc_list(ls);
27 | }
28 | free(node);
29 | }
30 |
31 | /*
32 | Recursively deallocates an AstNode*
33 | */
34 | void dealloc_ast_node(AstNode* node){
35 | if(node->type==AST_TYPE_ANY || node->type==AST_TYPE_VARARG || node->type==AST_TYPE_FUNC || node->type==AST_TYPE_BASIC || node->type==AST_TYPE_TUPLE){
36 | dealloc_ast_type(node);
37 | return;
38 | }
39 | if(node->type==AST_STMT || node->type==AST_DO || node->type==AST_ELSE){
40 | List* ls=(List*)(node->data);
41 | for(int a=0;an;a++){
42 | AstNode* e=(AstNode*)get_from_list(ls,a);
43 | dealloc_ast_node(e);
44 | }
45 | dealloc_list(ls);
46 | }
47 | else if(node->type==AST_LTUPLE){
48 | dealloc_list((List*)(node->data));
49 | }
50 | else if(node->type==AST_RETURN || node->type==AST_PAREN || node->type==AST_REQUIRE || node->type==AST_SUPER || node->type==AST_LIST){
51 | if(node->data) dealloc_ast_node((AstNode*)(node->data));
52 | }
53 | else if(node->type==AST_FIELD || node->type==AST_LOCAL || node->type==AST_TYPEDEF){
54 | StringAstNode* data=(StringAstNode*)(node->data);
55 | dealloc_ast_node(data->node);
56 | free(data);
57 | }
58 | else if(node->type==AST_PRIMITIVE){
59 | StringAstNode* data=(StringAstNode*)(node->data);
60 | free(data->node->data);
61 | free(data->node);
62 | free(data->text);
63 | free(data);
64 | }
65 | else if(node->type==AST_INTERFACE){
66 | InterfaceNode* data=(InterfaceNode*)(node->data);
67 | dealloc_ast_type(data->type);
68 | for(int a=0;als->n;a++){
69 | AstNode* e=get_from_list(data->ls,a);
70 | dealloc_ast_node(e);
71 | }
72 | dealloc_list(data->ls);
73 | free(data);
74 | }
75 | else if(node->type==AST_CLASS){
76 | ClassNode* data=(ClassNode*)(node->data);
77 | dealloc_list(data->interfaces);
78 | dealloc_ast_type(data->type);
79 | for(int a=0;als->n;a++){
80 | AstNode* e=get_from_list(data->ls,a);
81 | dealloc_ast_node(e);
82 | }
83 | dealloc_list(data->ls);
84 | free(data);
85 | }
86 | else if(node->type==AST_FUNCTION){
87 | FunctionNode* data=(FunctionNode*)(node->data);
88 | if(data->functype) dealloc_ast_type(data->functype);
89 | if(data->type) dealloc_ast_type(data->type);
90 | if(data->name) dealloc_ast_node(data->name);
91 | if(data->body){
92 | for(int a=0;abody->n;a++){
93 | AstNode* e=(AstNode*)get_from_list(data->body,a);
94 | dealloc_ast_node(e);
95 | }
96 | dealloc_list(data->body);
97 | }
98 | for(int a=0;aargs->n;a++){
99 | StringAstNode* e=(StringAstNode*)get_from_list(data->args,a);
100 | if(e->node) dealloc_ast_node(e->node);
101 | free(e);
102 | }
103 | dealloc_list(data->args);
104 | free(data);
105 | }
106 | else if(node->type==AST_BINARY || node->type==AST_UNARY || node->type==AST_DEFINE){
107 | BinaryNode* data=(BinaryNode*)(node->data);
108 | if(data->l) dealloc_ast_node(data->l);
109 | if(data->r) dealloc_ast_node(data->r);
110 | free(data);
111 | }
112 | else if(node->type==AST_REPEAT || node->type==AST_WHILE || node->type==AST_TUPLE){
113 | AstListNode* data=(AstListNode*)(node->data);
114 | if(data->node) dealloc_ast_node(data->node);
115 | for(int a=0;alist->n;a++){
116 | AstNode* e=get_from_list(data->list,a);
117 | dealloc_ast_node(e);
118 | }
119 | dealloc_list(data->list);
120 | free(data);
121 | }
122 | else if(node->type==AST_IF || node->type==AST_ELSEIF){
123 | IfNode* data=(IfNode*)(node->data);
124 | if(data->next) dealloc_ast_node(data->next);
125 | dealloc_ast_node(data->expr);
126 | for(int a=0;abody->n;a++){
127 | AstNode* e=get_from_list(data->body,a);
128 | dealloc_ast_node(e);
129 | }
130 | }
131 | else if(node->type==AST_CALL || node->type==AST_SET || node->type==AST_SUB){
132 | AstAstNode* data=(AstAstNode*)(node->data);
133 | if(data->r) dealloc_ast_node(data->r);
134 | dealloc_ast_node(data->l);
135 | free(data);
136 | }
137 | else if(node->type==AST_TABLE){
138 | TableNode* data=(TableNode*)(node->data);
139 | for(int a=0;avals->n;a++){
140 | AstNode* e=(AstNode*)get_from_list(data->vals,a);
141 | dealloc_ast_node(e);
142 | }
143 | dealloc_list(data->vals);
144 | dealloc_list(data->keys);
145 | free(data);
146 | }
147 | else if(node->type==AST_FORNUM){
148 | FornumNode* data=(FornumNode*)(node->data);
149 | if(data->num3) dealloc_ast_node(data->num3);
150 | dealloc_ast_node(data->num1);
151 | dealloc_ast_node(data->num2);
152 | for(int a=0;abody->n;a++){
153 | AstNode* e=(AstNode*)get_from_list(data->body,a);
154 | dealloc_ast_node(e);
155 | }
156 | dealloc_list(data->body);
157 | free(data);
158 | }
159 | else if(node->type==AST_FORIN){
160 | ForinNode* data=(ForinNode*)(node->data);
161 | dealloc_ast_node(data->tuple);
162 | dealloc_ast_node(data->lhs);
163 | for(int a=0;abody->n;a++){
164 | AstNode* e=(AstNode*)get_from_list(data->body,a);
165 | dealloc_ast_node(e);
166 | }
167 | dealloc_list(data->body);
168 | free(data);
169 | }
170 | free(node);
171 | }
172 |
173 | /*
174 | Creates a new AstNode
175 | */
176 | AstNode* new_node(int type,int line,void* data){
177 | AstNode* node=(AstNode*)malloc(sizeof(AstNode));
178 | node->line=line;
179 | node->type=type;
180 | node->data=data;
181 | return node;
182 | }
183 |
184 | /*
185 | Creates a new FunctionNode
186 | name can be AST_ID, AST_FIELD or NULL
187 | args is full of StringAstNodes
188 | */
189 | FunctionNode* new_function_node(AstNode* name,AstNode* type,List* args,List* body){
190 | FunctionNode* node=(FunctionNode*)malloc(sizeof(FunctionNode));
191 | node->is_constructor=0;
192 | node->functype=NULL;
193 | node->name=name;
194 | node->args=args;
195 | node->type=type;
196 | node->body=body;
197 | return node;
198 | }
199 |
200 | /*
201 | Creates a new AstListNode
202 | */
203 | AstListNode* new_ast_list_node(AstNode* ast,List* list){
204 | AstListNode* node=(AstListNode*)malloc(sizeof(AstListNode));
205 | node->list=list;
206 | node->node=ast;
207 | return node;
208 | }
209 |
210 | /*
211 | Creates a new table node
212 | The two lists should be of equal length
213 | keys is full of strings
214 | vals is full of AstNodes
215 | */
216 | TableNode* new_table_node(List* keys,List* vals){
217 | TableNode* node=(TableNode*)malloc(sizeof(TableNode));
218 | assert(keys->n==vals->n);
219 | node->keys=keys;
220 | node->vals=vals;
221 | return node;
222 | }
223 |
224 | /*
225 | Creates a new AstAstNode
226 | */
227 | AstAstNode* new_ast_ast_node(AstNode* l,AstNode* r){
228 | AstAstNode* node=(AstAstNode*)malloc(sizeof(AstAstNode));
229 | node->l=l;
230 | node->r=r;
231 | return node;
232 | }
233 |
234 | /*
235 | Creates a new StringAstNode
236 | */
237 | StringAstNode* new_string_ast_node(char* text,AstNode* ast){
238 | StringAstNode* node=(StringAstNode*)malloc(sizeof(StringAstNode));
239 | node->text=text;
240 | node->node=ast;
241 | return node;
242 | }
243 |
244 | /*
245 | Creates a StringAstNode* with copies of the provided arguments
246 | node->text is the name
247 | node->type is a AST_TYPE_BASIC node
248 | */
249 | StringAstNode* new_primitive_node(char* text,const char* type){
250 | char* stype=(char*)malloc(strlen(type)+1);
251 | strcpy(stype,type);
252 | char* stext=(char*)malloc(strlen(text)+1);
253 | strcpy(stext,text);
254 | return new_string_ast_node(stext,new_node(AST_TYPE_BASIC,-1,stype));
255 | }
256 |
257 | /*
258 | Creates a new for_num node
259 | body is full of AstNodes
260 | num3 may be NULL if the increment is not specified
261 | */
262 | FornumNode* new_fornum_node(char* name,AstNode* num1,AstNode* num2,AstNode* num3,List* body){
263 | FornumNode* node=(FornumNode*)malloc(sizeof(FornumNode));
264 | node->name=name;
265 | node->num1=num1;
266 | node->num2=num2;
267 | node->num3=num3;
268 | node->body=body;
269 | return node;
270 | }
271 |
272 | /*
273 | Creates a new for_in node
274 | body is full of AstNodes
275 | */
276 | ForinNode* new_forin_node(AstNode* lhs,AstNode* tuple,List* body){
277 | ForinNode* node=(ForinNode*)malloc(sizeof(ForinNode));
278 | node->tuple=tuple;
279 | node->body=body;
280 | node->lhs=lhs;
281 | return node;
282 | }
283 |
284 | /*
285 | Creates a new binary node
286 | */
287 | BinaryNode* new_binary_node(char* text,AstNode* l,AstNode* r){
288 | BinaryNode* node=(BinaryNode*)malloc(sizeof(BinaryNode));
289 | node->text=text;
290 | node->r=r;
291 | node->l=l;
292 | return node;
293 | }
294 |
295 | /*
296 | Creates a new interface node
297 | Sets its type to a AST_TYPE_BASIC of its own name
298 | ls is full of AST_FUNCTION
299 | */
300 | InterfaceNode* new_interface_node(char* name,char* parent,List* ls){
301 | InterfaceNode* node=(InterfaceNode*)malloc(sizeof(InterfaceNode));
302 | node->type=new_node(AST_TYPE_BASIC,-1,name);
303 | node->parent=parent;
304 | node->name=name;
305 | node->ls=ls;
306 | return node;
307 | }
308 |
309 | /*
310 | Creates a new class node
311 | Sets its type to a AST_TYPE_BASIC of its own name
312 | ls is full of AST_FUCTION and AST_DEFINE nodes
313 | interfaces is full of strings (interface names)
314 | */
315 | ClassNode* new_class_node(char* name,char* parent,List* interfaces,List* ls){
316 | ClassNode* node=(ClassNode*)malloc(sizeof(ClassNode));
317 | node->type=new_node(AST_TYPE_BASIC,-1,name);
318 | node->interfaces=interfaces;
319 | node->parent=parent;
320 | node->name=name;
321 | node->ls=ls;
322 | return node;
323 | }
324 |
325 | /*
326 | Creates an IfNode, which is used for both if and elseif statements
327 | */
328 | IfNode* new_if_node(AstNode* expr,AstNode* next,List* body){
329 | IfNode* node=(IfNode*)malloc(sizeof(IfNode));
330 | node->expr=expr;
331 | node->next=next;
332 | node->body=body;
333 | return node;
334 | }
335 |
336 | /*
337 | Creates an EqualTypesNode, which is used in the equivalent types graph
338 | These nodes help keep track of type relationships
339 | */
340 | EqualTypesNode* new_equal_types_node(char* name,AstNode* type,int relation,int scope){
341 | EqualTypesNode* node=(EqualTypesNode*)malloc(sizeof(EqualTypesNode));
342 | node->relation=relation;
343 | node->scope=scope;
344 | node->type=type;
345 | node->name=name;
346 | return node;
347 | }
348 |
349 | /*
350 | Creates a BinaryNode for a unary expression
351 | It also sets the type of this expression based on the operator (op)
352 | */
353 | BinaryNode* new_unary_node(char* op,AstNode* e){
354 | AstNode* type;
355 | if(!strcmp(op,"trust")) type=new_node(AST_TYPE_BASIC,-1,PRIMITIVE_NIL);
356 | else if(!strcmp(op,"#")) type=new_node(AST_TYPE_BASIC,-1,PRIMITIVE_INT);
357 | else type=new_node(AST_TYPE_BASIC,-1,PRIMITIVE_BOOL);
358 | return new_binary_node(op,e,type);
359 | }
360 |
--------------------------------------------------------------------------------
/src/parser.c:
--------------------------------------------------------------------------------
1 | #define MOONSHOT_PARSING
2 | #include "./internal.h"
3 | #undef MOONSHOT_PARSING
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #define UNARY_PRECEDENCE 6 // Precedence level for unary operators
10 | static List* tokens; // List of Tokens
11 | static int _i; // Index of the Token that's next to be consumed
12 |
13 | /*
14 | Wrapper for adding a compilation error
15 | Pulls the line number from a Token
16 | */
17 | static AstNode* error(Token* tk,const char* msg,...){
18 | va_list args;
19 | va_start(args,msg);
20 | add_error_internal(tk?tk->line:-1,msg,args);
21 | va_end(args);
22 | return NULL;
23 | }
24 |
25 | // Error wrappers that also deallocate data
26 | #define FREE_LIST(ret,ls) { \
27 | dealloc_list(ls); \
28 | return ret; \
29 | }
30 | #define FREE_AST_NODE(ret,node) { \
31 | dealloc_ast_node(node); \
32 | return ret; \
33 | }
34 | #define FREE_AST_NODE_LIST(ret,ls) { \
35 | for(int a=0;an;a++) dealloc_ast_node((AstNode*)get_from_list(ls,a)); \
36 | dealloc_list(ls); \
37 | return ret; \
38 | }
39 | #define FREE_STRING_AST_NODE_LIST(ret,ls) { \
40 | for(int a=0;an;a++){ \
41 | StringAstNode* node=(StringAstNode*)get_from_list(ls,a); \
42 | dealloc_ast_node(node->node); \
43 | free(node); \
44 | } \
45 | dealloc_list(ls); \
46 | return ret; \
47 | }
48 | #define FREE_AST_NODE_AND_LIST(ret,node,ls) { \
49 | dealloc_ast_node(node); \
50 | dealloc_list(ls); \
51 | return ret; \
52 | }
53 | #define FREE_2_LISTS(ret,ls1,ls2) { \
54 | dealloc_list(ls1); \
55 | dealloc_list(ls2); \
56 | return ret; \
57 | }
58 | #define FREE_2_AST_NODES(ret,node1,node2) { \
59 | dealloc_ast_node(node1); \
60 | dealloc_ast_node(node2); \
61 | return ret; \
62 | }
63 |
64 | /*
65 | The top-level parser interface function
66 | Takes in a Tokens list and returns an AST representation of your Moonshot source code
67 | */
68 | AstNode* parse(List* ls){
69 | _i=0;
70 | tokens=ls;
71 | AstNode* root=parse_stmt();
72 | if(root){
73 | Token* tk;
74 | while(_in){
75 | if((tk=(Token*)get_from_list(tokens,_i++))->type!=TK_SPACE){
76 | error(tk,"unparsed tokens",NULL);
77 | dealloc_ast_node(root);
78 | return NULL;
79 | }
80 | }
81 | }
82 | return root;
83 | }
84 |
85 | /*
86 | Consumes the next non-whitespace Token and returns it
87 | */
88 | static Token* consume(){
89 | while(_in && ((Token*)get_from_list(tokens,_i))->type==TK_SPACE) _i++;
90 | return (_in)?((Token*)get_from_list(tokens,_i++)):NULL;
91 | }
92 |
93 | /*
94 | Looks ahead at the next non-whitespace Token and returns it
95 | */
96 | static Token* check(){
97 | int a=_i;
98 | while(an && ((Token*)get_from_list(tokens,a))->type==TK_SPACE) a++;
99 | return (an)?((Token*)get_from_list(tokens,a)):NULL;
100 | }
101 |
102 | /*
103 | Consumes the next Token and returns it
104 | */
105 | static Token* consume_next(){
106 | if(_in) return (Token*)get_from_list(tokens,_i++);
107 | return NULL;
108 | }
109 |
110 | /*
111 | Looks ahead at the next Token and returns it
112 | */
113 | static Token* check_next(){
114 | if(_in) return (Token*)get_from_list(tokens,_i);
115 | return NULL;
116 | }
117 |
118 | /*
119 | Looks ahead the nth next non-whitespace Token and returns it
120 | */
121 | static Token* check_ahead(int n){
122 | int a=_i;
123 | while(n){
124 | while(an && ((Token*)get_from_list(tokens,a))->type==TK_SPACE) a++;
125 | if(n>1 && an) a++;
126 | n--;
127 | }
128 | return (an)?((Token*)get_from_list(tokens,a)):NULL;
129 | }
130 |
131 | /*
132 | Returns 1 if the Token is of type type
133 | */
134 | static int expect(Token* tk,int type){
135 | return tk && tk->type==type;
136 | }
137 |
138 | /*
139 | Returns 1 if the Token is of type type and has text val
140 | */
141 | static int specific(Token* tk,int type,const char* val){
142 | return tk && tk->type==type && !strcmp(tk->text,val);
143 | }
144 |
145 | /*
146 | Returns the precedence level of a binary operator
147 | */
148 | static int precedence(char* op){
149 | if(!strcmp(op,"as")) return 8;
150 | if(!strcmp(op,"^")) return 7;
151 | if(!strcmp(op,"*") || !strcmp(op,"/")) return 5;
152 | if(!strcmp(op,"+") || !strcmp(op,"-")) return 4;
153 | if(!strcmp(op,"..")) return 3;
154 | if(!strcmp(op,"<=") || !strcmp(op,">=") || !strcmp(op,"<") || !strcmp(op,">") || !strcmp(op,"==") || !strcmp(op,"~=")) return 2;
155 | if(!strcmp(op,"and")) return 1;
156 | return 0;
157 | }
158 |
159 | // Statement block parsers
160 | AstNode* parse_stmt(){
161 | int line=-1;
162 | Token* tk;
163 | AstNode* node;
164 | List* ls=new_default_list();
165 | while(1){
166 | tk=check();
167 | if(!tk) break;
168 | if(line<0) line=tk->line;
169 | if(expect(tk,TK_FUNCTION)) node=parse_function(NULL,1);
170 | else if(expect(tk,TK_IF)) node=parse_if();
171 | else if(expect(tk,TK_SUPER)) node=parse_super();
172 | else if(expect(tk,TK_CLASS)) node=parse_class();
173 | else if(expect(tk,TK_INTERFACE)) node=parse_interface();
174 | else if(expect(tk,TK_TYPEDEF)) node=parse_typedef();
175 | else if(expect(tk,TK_REQUIRE)) node=parse_require();
176 | else if(expect(tk,TK_RETURN)) node=parse_return();
177 | else if(expect(tk,TK_DBCOLON)) node=parse_label();
178 | else if(expect(tk,TK_LOCAL)) node=parse_local();
179 | else if(expect(tk,TK_BREAK)) node=parse_break();
180 | else if(expect(tk,TK_REPEAT)) node=parse_repeat();
181 | else if(expect(tk,TK_WHILE)) node=parse_while();
182 | else if(expect(tk,TK_GOTO)) node=parse_goto();
183 | else if(expect(tk,TK_DO)) node=parse_do();
184 | else if(specific(tk,TK_BINARY,"*")) node=parse_function_or_define();
185 | else if(expect(tk,TK_CONSTRUCTOR)) node=error(tk,"invalid constructor without a class",NULL);
186 | else if(specific(tk,TK_PAREN,"(")){
187 | AstNode* type=parse_type();
188 | if(type) node=parse_function(type,1);
189 | else node=NULL;
190 | }else if(expect(tk,TK_FOR)){
191 | tk=check_ahead(3);
192 | if(specific(tk,TK_MISC,",") || expect(tk,TK_IN)) node=parse_forin();
193 | else if(specific(tk,TK_MISC,"=")) node=parse_fornum();
194 | else node=error(tk,"invalid loop",NULL);
195 | }else if(expect(tk,TK_NAME) || expect(tk,TK_VAR)){
196 | tk=check_ahead(2);
197 | if(specific(tk,TK_PAREN,"(") || specific(tk,TK_SQUARE,"[") || specific(tk,TK_MISC,"=") || specific(tk,TK_MISC,".") || specific(tk,TK_MISC,",")) node=parse_set_or_call();
198 | else if(expect(tk,TK_VAR) || expect(tk,TK_NAME)) node=parse_function_or_define();
199 | else node=error(tk,"invalid statement",NULL);
200 | }else{
201 | break;
202 | }
203 | if(node) add_to_list(ls,node);
204 | else FREE_AST_NODE_LIST(NULL,ls);
205 | }
206 | return new_node(AST_STMT,line,ls);
207 | }
208 | AstNode* parse_do(){
209 | Token* tk=consume();
210 | if(!expect(tk,TK_DO)) return error(tk,"invalid do block",NULL);
211 | int line=tk->line;
212 | AstNode* node=parse_stmt();
213 | if(!node) return NULL;
214 | tk=consume();
215 | if(!expect(tk,TK_END)) return error(tk,"unclosed do block",NULL);
216 | return new_node(AST_DO,line,(List*)(node->data));
217 | }
218 |
219 | // Entity parsers (classes and interfaces)
220 | AstNode* parse_interface(){
221 | char* parent=NULL;
222 | Token* tk=consume();
223 | if(!expect(tk,TK_INTERFACE)) return error(tk,"invalid interface",NULL);
224 | int line=tk->line;
225 | tk=consume();
226 | if(!expect(tk,TK_NAME)) return error(tk,"invalid name for interface",NULL);
227 | char* name=tk->text;
228 | tk=check();
229 | if(expect(tk,TK_EXTENDS)){
230 | consume();
231 | tk=consume();
232 | if(!expect(tk,TK_NAME)) return error(tk,"invalid parent for interface %s",name);
233 | parent=tk->text;
234 | }
235 | tk=consume();
236 | if(!expect(tk,TK_WHERE)) return error(tk,"invalid interface %s",name);
237 | tk=check();
238 | List* ls=new_default_list();
239 | while(tk && !expect(tk,TK_END)){
240 | AstNode* type=NULL;
241 | if(!expect(tk,TK_FUNCTION)){
242 | type=parse_type();
243 | if(!type) FREE_AST_NODE_LIST(NULL,ls);
244 | }
245 | AstNode* func=parse_function(type,0);
246 | if(!func){
247 | dealloc_ast_type(type);
248 | FREE_AST_NODE_LIST(NULL,ls);
249 | }
250 | add_to_list(ls,func);
251 | tk=check();
252 | }
253 | tk=consume();
254 | if(!expect(tk,TK_END)) FREE_AST_NODE_LIST(error(tk,"invalid interface %s",NULL),ls);
255 | return new_node(AST_INTERFACE,line,new_interface_node(name,parent,ls));
256 | }
257 | AstNode* parse_class(){
258 | char* parent=NULL;
259 | Token* tk=consume();
260 | if(!expect(tk,TK_CLASS)) return error(tk,"invalid class",NULL);
261 | int line=tk->line;
262 | tk=consume();
263 | if(!expect(tk,TK_NAME)) return error(tk,"invalid name for class",NULL);
264 | char* name=tk->text;
265 | tk=check();
266 | if(expect(tk,TK_EXTENDS)){
267 | consume();
268 | tk=consume();
269 | if(!expect(tk,TK_NAME)) return error(tk,"invalid parent for class %s",name);
270 | parent=tk->text;
271 | tk=check();
272 | }
273 | List* interfaces=new_default_list();
274 | if(expect(tk,TK_IMPLEMENTS)){
275 | consume();
276 | tk=consume();
277 | if(!expect(tk,TK_NAME)) FREE_LIST(error(tk,"invalid interface for class %s",name),interfaces);
278 | add_to_list(interfaces,tk->text);
279 | tk=check();
280 | while(specific(tk,TK_MISC,",")){
281 | consume();
282 | tk=consume();
283 | if(!expect(tk,TK_NAME)) FREE_LIST(error(tk,"invalid interface for class %s",name),interfaces);
284 | add_to_list(interfaces,tk->text);
285 | tk=check();
286 | }
287 | }
288 | tk=consume();
289 | if(!expect(tk,TK_WHERE)) FREE_LIST(error(tk,"invalid class %s",name),interfaces);
290 | tk=check();
291 | List* ls=new_default_list();
292 | while(tk && !expect(tk,TK_END)){
293 | AstNode* node;
294 | if(expect(tk,TK_CONSTRUCTOR)) node=parse_constructor(name);
295 | else if(expect(tk,TK_FUNCTION)) node=parse_function(NULL,1);
296 | else node=parse_function_or_define();
297 | if(!node){
298 | for(int a=0;an;a++) dealloc_ast_node((AstNode*)get_from_list(ls,a));
299 | FREE_2_LISTS(NULL,interfaces,ls);
300 | }
301 | add_to_list(ls,node);
302 | tk=check();
303 | }
304 | tk=consume();
305 | if(!expect(tk,TK_END)){
306 | for(int a=0;an;a++) dealloc_ast_node((AstNode*)get_from_list(ls,a));
307 | FREE_2_LISTS(error(tk,"invalid class %s",name),interfaces,ls);
308 | }
309 | return new_node(AST_CLASS,line,new_class_node(name,parent,interfaces,ls));
310 | }
311 |
312 | // Type parsers
313 | AstNode* parse_typedef(){
314 | Token* tk=consume();
315 | if(!expect(tk,TK_TYPEDEF)) return error(tk,"invalid typedef",NULL);
316 | int line=tk->line;
317 | tk=consume();
318 | if(!expect(tk,TK_NAME)) return error(tk,"invalid name for typedef",NULL);
319 | char* name=tk->text;
320 | AstNode* node=parse_type();
321 | if(!node) return NULL;
322 | return new_node(AST_TYPEDEF,line,new_string_ast_node(name,node));
323 | }
324 | static AstNode* parse_basic_type(){
325 | Token* tk=check();
326 | if(expect(tk,TK_VAR)){
327 | consume();
328 | return new_node(AST_TYPE_ANY,tk->line,NULL);
329 | }else if(expect(tk,TK_DOTS)){
330 | consume();
331 | return new_node(AST_TYPE_VARARG,tk->line,NULL);
332 | }else if(expect(tk,TK_NAME)){
333 | consume();
334 | return new_node(AST_TYPE_BASIC,tk->line,tk->text);
335 | }else if(specific(tk,TK_BINARY,"*")){
336 | int line=tk->line;
337 | consume();
338 | AstNode* node=parse_type();
339 | if(!node) return NULL;
340 | if(node->type==AST_TYPE_VARARG){
341 | (node);
342 | return error(tk,"invalid variadic member in function type",NULL);
343 | }
344 | tk=check();
345 | while(specific(tk,TK_PAREN,"(")){
346 | consume();
347 | tk=check();
348 | List* ls=new_default_list();
349 | while(tk && !specific(tk,TK_PAREN,")")){
350 | AstNode* arg=parse_type();
351 | if(!arg){
352 | for(int a=0;an;a++) dealloc_ast_type((AstNode*)get_from_list(ls,a));
353 | FREE_AST_NODE_AND_LIST(error(tk,"invalid function type",NULL),node,ls);
354 | }
355 | add_to_list(ls,arg);
356 | tk=check();
357 | if(specific(tk,TK_MISC,",")) consume();
358 | }
359 | node=new_node(AST_TYPE_FUNC,line,new_ast_list_node(node,ls));
360 | tk=consume();
361 | if(!specific(tk,TK_PAREN,")")){
362 | FREE_AST_NODE(error(tk,"unclosed function type",NULL),node);
363 | }
364 | tk=check();
365 | }
366 | return node;
367 | }
368 | return error(tk,"invalid type",NULL);
369 | }
370 | AstNode* parse_type(){
371 | Token* tk=check();
372 | if(specific(tk,TK_PAREN,"(")){
373 | int line=tk->line;
374 | int commas=0;
375 | consume();
376 | AstNode* e=parse_basic_type();
377 | if(!e) return NULL;
378 | if(e->type==AST_TYPE_VARARG){
379 | dealloc_ast_type(e);
380 | return error(tk,"invalid variadic member in tuple type",NULL);
381 | }
382 | List* ls=new_default_list();
383 | add_to_list(ls,e);
384 | tk=check();
385 | while(specific(tk,TK_MISC,",")){
386 | consume();
387 | e=parse_basic_type();
388 | if(!e) FREE_AST_NODE_LIST(NULL,ls);
389 | if(e->type==AST_TYPE_VARARG){
390 | (e);
391 | FREE_AST_NODE_LIST(error(tk,"invalid variadic member in tuple type",NULL),ls);
392 | }
393 | add_to_list(ls,e);
394 | tk=check();
395 | commas++;
396 | }
397 | tk=consume();
398 | if(!specific(tk,TK_PAREN,")")) FREE_AST_NODE_LIST(error(tk,"unclosed tuple type",NULL),ls);
399 | if(!commas) FREE_AST_NODE_LIST(error(tk,"too few elements in tuple type",NULL),ls);
400 | return new_node(AST_TYPE_TUPLE,line,ls);
401 | }
402 | return parse_basic_type();
403 | }
404 |
405 | // Variable parse functions
406 | AstNode* parse_define(AstNode* type){
407 | AstNode* expr=NULL;
408 | Token* tk=consume();
409 | if(!expect(tk,TK_NAME)) return error(tk,"invalid name for definition",NULL);
410 | int line=tk->line;
411 | char* name=tk->text;
412 | tk=check();
413 | if(specific(tk,TK_MISC,"=")){
414 | consume();
415 | expr=parse_expr();
416 | if(!expr) return NULL;
417 | }
418 | return new_node(AST_DEFINE,line,new_binary_node(name,type,expr));
419 | }
420 | AstNode* parse_set_or_call(){
421 | AstNode* lhs=parse_potential_tuple_lhs();
422 | if(!lhs) return NULL;
423 | Token* tk=check();
424 | if(expect(tk,TK_PAREN)){
425 | if(lhs->type==AST_LTUPLE) FREE_AST_NODE(error(tk,"invalid function call",NULL),lhs);
426 | return parse_call(lhs);
427 | }
428 | tk=consume();
429 | if(!specific(tk,TK_MISC,"=")) FREE_AST_NODE(error(tk,"invalid set statement",NULL),lhs);
430 | AstNode* expr=parse_tuple();
431 | if(!expr) FREE_AST_NODE(NULL,lhs);
432 | return new_node(AST_SET,lhs->line,new_ast_ast_node(lhs,expr));
433 | }
434 | AstNode* parse_function_or_define(){
435 | AstNode* type=parse_type();
436 | if(!type) return NULL;
437 | Token* tk=check();
438 | if(!expect(tk,TK_NAME)) FREE_AST_NODE(error(tk,"invalid statement",NULL),type);
439 | tk=check_ahead(2);
440 | if(specific(tk,TK_PAREN,"(")) return parse_function(type,1);
441 | return parse_define(type);
442 | }
443 | AstNode* parse_potential_tuple_lhs(){
444 | AstNode* node=parse_lhs();
445 | Token* tk=check();
446 | if(specific(tk,TK_MISC,",")){
447 | int line=tk->line;
448 | if(node->type!=AST_ID) FREE_AST_NODE(error(tk,"Invalid left-hand entity in tuple",NULL),node);
449 | List* ls=new_default_list();
450 | add_to_list(ls,node);
451 | while(specific(tk,TK_MISC,",")){
452 | consume();
453 | tk=consume();
454 | if(!expect(tk,TK_NAME)) FREE_AST_NODE_LIST(error(tk,"invalid left-hand tuple",NULL),ls);
455 | add_to_list(ls,new_node(AST_ID,line,tk->text));
456 | tk=check();
457 | }
458 | return new_node(AST_LTUPLE,line,new_ast_list_node(NULL,ls));
459 | }
460 | return node;
461 | }
462 | AstNode* parse_lhs(){
463 | Token* tk=consume();
464 | if(!expect(tk,TK_NAME)) return error(tk,"invalid left-hand side of statement",NULL);
465 | int line=tk->line;
466 | AstNode* node=new_node(AST_ID,line,tk->text);
467 | tk=check_next();
468 | while(specific(tk,TK_MISC,".") || specific(tk,TK_SQUARE,"[")){
469 | if(specific(tk,TK_SQUARE,"[")){
470 | consume();
471 | AstNode* r=parse_expr();
472 | if(!r) FREE_AST_NODE(NULL,node);
473 | node=new_node(AST_SUB,line,new_ast_ast_node(node,r));
474 | tk=consume();
475 | if(!specific(tk,TK_SQUARE,"]")) FREE_AST_NODE(error(tk,"invalid property",NULL),node);
476 | }
477 | if(specific(tk,TK_MISC,".")){
478 | consume();
479 | tk=consume();
480 | if(!expect(tk,TK_NAME)) FREE_AST_NODE(error(tk,"invalid field",NULL),node);
481 | node=new_node(AST_FIELD,line,new_string_ast_node(tk->text,node));
482 | }
483 | tk=check_next();
484 | }
485 | return node;
486 | }
487 | AstNode* parse_local(){
488 | AstNode* node=NULL;
489 | Token* tk=consume();
490 | if(!expect(tk,TK_LOCAL)) return error(tk,"invalid local variable declaration",NULL);
491 | int line=tk->line;
492 | tk=consume();
493 | if(!expect(tk,TK_NAME)) return error(tk,"invalid name for local variable",NULL);
494 | char* name=tk->text;
495 | tk=check();
496 | if(specific(tk,TK_MISC,"=")){
497 | consume();
498 | node=parse_expr();
499 | if(!node) return NULL;
500 | }
501 | return new_node(AST_LOCAL,line,new_string_ast_node(name,node));
502 | }
503 |
504 | // Function parsers
505 | static List* parse_function_params(){
506 | Token* tk=consume();
507 | if(!specific(tk,TK_PAREN,"(")) return (List*)error(tk,"invalid function",NULL);
508 | tk=check();
509 | List* args=new_default_list();
510 | while(tk && !specific(tk,TK_PAREN,")")){
511 | AstNode* arg_type=NULL;
512 | tk=check();
513 | if(expect(tk,TK_DOTS)){
514 | add_to_list(args,new_string_ast_node(tk->text,NULL));
515 | consume();
516 | break;
517 | }
518 | tk=check_ahead(2);
519 | if(!specific(tk,TK_MISC,",") && !specific(tk,TK_PAREN,")")){
520 | arg_type=parse_type();
521 | if(!arg_type) FREE_STRING_AST_NODE_LIST(NULL,args);
522 | }
523 | tk=consume();
524 | if(!expect(tk,TK_NAME)){
525 | if(arg_type) dealloc_ast_node(arg_type);
526 | FREE_STRING_AST_NODE_LIST((List*)error(tk,"invalid function argument",NULL),args);
527 | }
528 | add_to_list(args,new_string_ast_node(tk->text,arg_type));
529 | tk=check();
530 | if(specific(tk,TK_MISC,",")){
531 | consume();
532 | tk=check();
533 | }
534 | }
535 | tk=consume();
536 | if(!specific(tk,TK_PAREN,")")){
537 | FREE_STRING_AST_NODE_LIST((List*)error(tk,"unclosed function arguments",NULL),args);
538 | }
539 | return args;
540 | }
541 | AstNode* parse_function(AstNode* type,int include_body){
542 | int line;
543 | Token* tk;
544 | int typed=(type!=NULL);
545 | if(!typed){
546 | tk=consume();
547 | if(!expect(tk,TK_FUNCTION)) return error(tk,"invalid function",NULL);
548 | type=new_node(AST_TYPE_ANY,-1,NULL);
549 | }
550 | AstNode* name=NULL;
551 | tk=check();
552 | if(expect(tk,TK_NAME)){
553 | line=tk->line;
554 | name=parse_lhs();
555 | if(!name){
556 | if(!typed) free(type);
557 | return NULL;
558 | }
559 | if(typed && name->type!=AST_ID){
560 | if(!typed) free(type);
561 | return error(tk,"cannot define typed methods outside of a class or interface",NULL);
562 | }
563 | }else if(typed){
564 | if(!expect(tk,TK_FUNCTION)) return error(tk,"invalid anonymous typed function",NULL);
565 | line=tk->line;
566 | consume();
567 | }
568 | List* args=parse_function_params();
569 | if(!args){
570 | if(!typed) free(type);
571 | if(name) FREE_AST_NODE(NULL,name);
572 | return NULL;
573 | }
574 | List* ls=NULL;
575 | if(include_body){
576 | AstNode* node=parse_stmt();
577 | if(!node){
578 | if(!typed) free(type);
579 | if(name) FREE_AST_NODE(NULL,name);
580 | FREE_STRING_AST_NODE_LIST(NULL,args);
581 | }
582 | tk=consume();
583 | if(!expect(tk,TK_END)){
584 | if(!typed) free(type);
585 | dealloc_ast_node(node);
586 | if(name) FREE_AST_NODE(NULL,name);
587 | FREE_STRING_AST_NODE_LIST(error(tk,"unclosed function",NULL),args);
588 | }
589 | ls=(List*)(node->data);
590 | free(node);
591 | }
592 | return new_node(AST_FUNCTION,line,new_function_node(name,type,args,ls));
593 | }
594 | AstNode* parse_constructor(char* classname){
595 | Token* tk=consume();
596 | if(!expect(tk,TK_CONSTRUCTOR)) return error(tk,"invalid constructor for class %s",classname);
597 | int line=tk->line;
598 | List* args=parse_function_params();
599 | if(!args) return NULL;
600 | AstNode* node=parse_stmt();
601 | if(!node) FREE_AST_NODE_LIST(NULL,args);
602 | tk=consume();
603 | if(!expect(tk,TK_END)) FREE_AST_NODE_LIST(error(tk,"unclosed constructor for class %s",classname),args);
604 | FunctionNode* data=new_function_node(NULL,new_node(AST_TYPE_BASIC,line,classname),args,(List*)(node->data));
605 | data->is_constructor=1;
606 | free(node);
607 | return new_node(AST_FUNCTION,line,data);
608 | }
609 | static AstNode* parse_arg_tuple(){
610 | AstNode* args=NULL;
611 | Token* tk=consume_next();
612 | if(!specific(tk,TK_PAREN,"(")) return error(tk,"invalid function call",NULL);
613 | int line=tk->line;
614 | tk=check();
615 | if(tk && !specific(tk,TK_PAREN,")")){
616 | args=parse_tuple();
617 | if(!args) return NULL;
618 | }else{
619 | args=new_node(AST_NONE,line,NULL);
620 | }
621 | tk=consume();
622 | if(!specific(tk,TK_PAREN,")")){
623 | error(tk,"unclosed function call",NULL);
624 | if(args){
625 | FREE_AST_NODE(NULL,args);
626 | }
627 | return NULL;
628 | }
629 | return args;
630 | }
631 | AstNode* parse_super(){
632 | Token* tk=consume();
633 | if(!expect(tk,TK_SUPER)) return error(tk,"invalid super method invocation",NULL);
634 | int line=tk->line;
635 | AstNode* args=parse_arg_tuple();
636 | if(!args) return NULL;
637 | if(args->type==AST_NONE){
638 | free(args);
639 | args=NULL;
640 | }
641 | return new_node(AST_SUPER,line,args);
642 | }
643 | AstNode* parse_call(AstNode* lhs){
644 | AstNode* args=parse_arg_tuple();
645 | if(!args) return NULL;
646 | int line=args->line;
647 | if(args->type==AST_NONE){
648 | free(args);
649 | args=NULL;
650 | }
651 | return new_node(AST_CALL,line,new_ast_ast_node(lhs,args));
652 | }
653 |
654 | // Conditional loop statements
655 | AstNode* parse_repeat(){
656 | Token* tk=consume();
657 | if(!expect(tk,TK_REPEAT)) return error(tk,"invalid repeat statement",NULL);
658 | int line=tk->line;
659 | AstNode* body=parse_stmt();
660 | if(!body) return NULL;
661 | tk=consume();
662 | if(!expect(tk,TK_UNTIL)) FREE_AST_NODE(error(tk,"repeat statement missing until keyword",NULL),body);
663 | AstNode* expr=parse_expr();
664 | if(!expr) FREE_AST_NODE(NULL,body);
665 | return new_node(AST_REPEAT,line,new_ast_list_node(expr,(List*)(body->data)));
666 | }
667 | AstNode* parse_while(){
668 | Token* tk=consume();
669 | if(!expect(tk,TK_WHILE)) return error(tk,"invalid while statement",NULL);
670 | int line=tk->line;
671 | AstNode* expr=parse_expr();
672 | if(!expr) return NULL;
673 | tk=consume();
674 | if(!expect(tk,TK_DO)) FREE_AST_NODE(error(tk,"while statement missing do keyword",NULL),expr);
675 | AstNode* body=parse_stmt();
676 | if(!body) FREE_AST_NODE(NULL,expr);
677 | tk=consume();
678 | if(!expect(tk,TK_END)) FREE_2_AST_NODES(error(tk,"unclosed while statement",NULL),expr,body);
679 | return new_node(AST_WHILE,line,new_ast_list_node(expr,(List*)(body->data)));
680 | }
681 |
682 | // If statements
683 | AstNode* parse_if(){
684 | Token* tk=consume();
685 | AstNode* next=NULL;
686 | if(!expect(tk,TK_IF)) return error(tk,"invalid if statement",NULL);
687 | int line=tk->line;
688 | AstNode* expr=parse_expr();
689 | if(!expr) return NULL;
690 | tk=consume();
691 | if(!expect(tk,TK_THEN)) FREE_AST_NODE(error(tk,"invalid expression in if statement",NULL),expr);
692 | AstNode* body=parse_stmt();
693 | if(!body) FREE_AST_NODE(NULL,expr);
694 | tk=check();
695 | if(expect(tk,TK_ELSEIF)){
696 | next=parse_elseif();
697 | if(!next) FREE_2_AST_NODES(NULL,expr,body);
698 | }else if(expect(tk,TK_ELSE)){
699 | next=parse_else();
700 | if(!next) FREE_2_AST_NODES(NULL,expr,body);
701 | }else if(expect(tk,TK_END)){
702 | consume();
703 | }else{
704 | FREE_2_AST_NODES(error(tk,"unclosed if statement",NULL),expr,body);
705 | }
706 | List* ls=(List*)(body->data);
707 | free(body);
708 | return new_node(AST_IF,line,new_if_node(expr,next,ls));
709 | }
710 | AstNode* parse_elseif(){
711 | Token* tk=consume();
712 | AstNode* next=NULL;
713 | if(!expect(tk,TK_ELSEIF)) return error(tk,"invalid elseif clause",NULL);
714 | int line=tk->line;
715 | AstNode* expr=parse_expr();
716 | if(!expr) return NULL;
717 | tk=consume();
718 | if(!expect(tk,TK_THEN)) FREE_AST_NODE(error(tk,"invalid expression in elseif clause",NULL),expr);
719 | AstNode* body=parse_stmt();
720 | if(!body) FREE_AST_NODE(NULL,expr);
721 | tk=check();
722 | if(expect(tk,TK_ELSEIF)){
723 | next=parse_elseif();
724 | if(!next) FREE_2_AST_NODES(NULL,expr,body);
725 | }else if(expect(tk,TK_ELSE)){
726 | next=parse_else();
727 | if(!next) FREE_2_AST_NODES(NULL,expr,body);
728 | }else if(expect(tk,TK_END)){
729 | consume();
730 | }else{
731 | FREE_2_AST_NODES(error(tk,"unclosed elseif clause",NULL),expr,body);
732 | }
733 | List* ls=(List*)(body->data);
734 | free(body);
735 | return new_node(AST_ELSEIF,line,new_if_node(expr,next,ls));
736 | }
737 | AstNode* parse_else(){
738 | Token* tk=consume();
739 | if(!expect(tk,TK_ELSE)) return error(tk,"invalid else clause",NULL);
740 | int line=tk->line;
741 | AstNode* body=parse_stmt();
742 | if(!body) return NULL;
743 | tk=consume();
744 | if(!expect(tk,TK_END)){
745 | FREE_AST_NODE(error(tk,"unclosed else clause",NULL),body);
746 | }
747 | List* ls=(List*)(body->data);
748 | free(body);
749 | return new_node(AST_ELSE,line,ls);
750 | }
751 |
752 | // For statements
753 | AstNode* parse_fornum(){
754 | Token* tk=consume();
755 | AstNode *num1,*num2,*num3=NULL;
756 | if(!expect(tk,TK_FOR)) return error(tk,"invalid for loop",NULL);
757 | int line=tk->line;
758 | tk=consume();
759 | if(!expect(tk,TK_NAME)) return error(tk,"invalid counter name in for loop",NULL);
760 | char* name=tk->text;
761 | tk=consume();
762 | if(!specific(tk,TK_MISC,"=")) return error(tk,"invalid for loop with counter %s",name);
763 | AstNode* node=parse_tuple();
764 | if(!node) return NULL;
765 | AstListNode* tuple=(AstListNode*)(node->data);
766 | if(tuple->list->n<2) FREE_AST_NODE(error(NULL,"Not enough values in for loop",NULL),node);
767 | if(tuple->list->n>3) FREE_AST_NODE(error(NULL,"Too many values in for loop",NULL),node);
768 | num1=(AstNode*)get_from_list(tuple->list,0);
769 | num2=(AstNode*)get_from_list(tuple->list,1);
770 | if(tuple->list->n==3) num3=(AstNode*)get_from_list(tuple->list,2);
771 | tk=consume();
772 | if(!expect(tk,TK_DO)){
773 | if(num3) dealloc_ast_node(num3);
774 | FREE_2_AST_NODES(error(tk,"invalid for loop with counter",name),num1,num2);
775 | }
776 | AstNode* body=parse_stmt();
777 | if(!body){
778 | if(num3) dealloc_ast_node(num3);
779 | FREE_2_AST_NODES(NULL,num1,num2);
780 | }
781 | tk=consume();
782 | if(!expect(tk,TK_END)){
783 | dealloc_ast_node(body);
784 | if(num3) dealloc_ast_node(num3);
785 | FREE_2_AST_NODES(error(tk,"unclosed for loop with counter %s",name),num1,num2);
786 | }
787 | return new_node(AST_FORNUM,line,new_fornum_node(name,num1,num2,num3,(List*)(body->data)));
788 | }
789 | AstNode* parse_forin(){
790 | Token* tk=consume();
791 | if(!expect(tk,TK_FOR)) return error(tk,"invalid for loop",NULL);
792 | int line=tk->line;
793 | tk=consume();
794 | if(!expect(tk,TK_NAME)) return error(tk,"invalid name in for loop",NULL);
795 | List* lhs=new_default_list();
796 | add_to_list(lhs,new_node(AST_ID,line,tk->text));
797 | tk=check();
798 | while(specific(tk,TK_MISC,",")){
799 | consume();
800 | tk=consume();
801 | if(!expect(tk,TK_NAME)) FREE_AST_NODE_LIST(error(tk,"invalid name in for loop",NULL),lhs);
802 | add_to_list(lhs,new_node(AST_ID,line,tk->text));
803 | tk=check();
804 | }
805 | tk=consume();
806 | if(!expect(tk,TK_IN)) FREE_AST_NODE_LIST(error(tk,"missing in keyword in for loop",NULL),lhs);
807 | AstNode* tuple=parse_tuple();
808 | if(!tuple) FREE_AST_NODE_LIST(NULL,lhs);
809 | tk=consume();
810 | if(!expect(tk,TK_DO)){
811 | dealloc_ast_node(tuple);
812 | FREE_AST_NODE_LIST(error(tk,"missing do keyword in for loop",NULL),lhs);
813 | }
814 | AstNode* body=parse_stmt();
815 | if(!body){
816 | dealloc_ast_node(tuple);
817 | FREE_AST_NODE_LIST(NULL,lhs);
818 | }
819 | tk=consume();
820 | if(!expect(tk,TK_END)){
821 | dealloc_ast_node(body);
822 | dealloc_ast_node(tuple);
823 | FREE_AST_NODE_LIST(error(tk,"missing end keyword in for loop",NULL),lhs);
824 | }
825 | AstNode* lhs_node=new_node(AST_LTUPLE,line,new_ast_list_node(NULL,lhs));
826 | return new_node(AST_FORIN,line,new_forin_node(lhs_node,tuple,(List*)(body->data)));
827 | }
828 |
829 | // Label-based statements
830 | AstNode* parse_label(){
831 | Token* tk=consume();
832 | if(!expect(tk,TK_DBCOLON)) return error(tk,"invalid label",NULL);
833 | int line=tk->line;
834 | tk=consume();
835 | if(!expect(tk,TK_NAME)) return error(tk,"invalid label",NULL);
836 | char* text=tk->text;
837 | tk=consume();
838 | if(!expect(tk,TK_DBCOLON)) return error(tk,"invalid label",NULL);
839 | return new_node(AST_LABEL,line,text);
840 | }
841 | AstNode* parse_goto(){
842 | Token* tk=consume();
843 | if(!expect(tk,TK_GOTO)) return error(tk,"invalid goto statement",NULL);
844 | int line=tk->line;
845 | tk=consume();
846 | if(!expect(tk,TK_NAME)) return error(tk,"invalid goto statement",NULL);
847 | char* text=tk->text;
848 | return new_node(AST_GOTO,line,text);
849 | }
850 |
851 | // Basic control statements
852 | AstNode* parse_break(){
853 | Token* tk=consume();
854 | if(!expect(tk,TK_BREAK)) return error(tk,"invalid break",NULL);
855 | return new_node(AST_BREAK,tk->line,NULL);
856 | }
857 | AstNode* parse_require(){
858 | Token* tk=consume();
859 | if(!expect(tk,TK_REQUIRE)) return error(tk,"invalid require statement",NULL);
860 | AstNode* expr=parse_string();
861 | if(!expr) return NULL;
862 | return new_node(AST_REQUIRE,tk->line,expr);
863 | }
864 | AstNode* parse_return(){
865 | AstNode* node=NULL;
866 | Token* tk=consume();
867 | if(!expect(tk,TK_RETURN)) return error(tk,"invalid return statement",NULL);
868 | int line=tk->line;
869 | tk=check();
870 | if(!expect(tk,TK_END)){
871 | node=parse_tuple();
872 | if(!node) return NULL;
873 | }
874 | return new_node(AST_RETURN,line,node);
875 | }
876 |
877 | // Parse tables and lists
878 | AstNode* parse_table_or_list(){
879 | Token* tk=consume();
880 | if(!specific(tk,TK_CURLY,"{")) return error(tk,"invalid table",NULL);
881 | int line=tk->line;
882 | tk=check();
883 | if(specific(tk,TK_CURLY,"}")){
884 | consume();
885 | return new_node(AST_LIST,line,NULL);
886 | }
887 | tk=check_ahead(2);
888 | if(specific(tk,TK_MISC,"=")){
889 | return parse_table();
890 | }
891 | return parse_list();
892 | }
893 | AstNode* parse_list(){
894 | AstNode* tuple=parse_tuple();
895 | if(!tuple) return NULL;
896 | Token* tk=consume();
897 | if(!specific(tk,TK_CURLY,"}")){
898 | if(tk) error(tk,"missing comma in list",NULL);
899 | else error(tk,"unclosed list",NULL);
900 | FREE_AST_NODE(NULL,tuple);
901 | }
902 | return new_node(AST_LIST,tk->line,tuple);
903 | }
904 | AstNode* parse_table(){
905 | List* keys=new_default_list();
906 | List* vals=new_default_list();
907 | Token* tk=consume();
908 | assert(tk);
909 | int line=tk->line;
910 | while(tk && !specific(tk,TK_CURLY,"}")){
911 | if(!expect(tk,TK_NAME)){
912 | dealloc_list(keys);
913 | FREE_AST_NODE_LIST(error(tk,"invalid table key",NULL),vals);
914 | }
915 | char* k=tk->text;
916 | add_to_list(keys,k);
917 | tk=consume();
918 | if(!specific(tk,TK_MISC,"=")){
919 | dealloc_list(keys);
920 | FREE_AST_NODE_LIST(error(tk,"table key %s missing equals sign",k),vals);
921 | }
922 | AstNode* node=parse_expr();
923 | if(!node){
924 | dealloc_list(keys);
925 | FREE_AST_NODE_LIST(NULL,vals);
926 | }
927 | add_to_list(vals,node);
928 | tk=consume();
929 | if(!specific(tk,TK_CURLY,"}")){
930 | if(!specific(tk,TK_MISC,",")){
931 | dealloc_list(keys);
932 | FREE_AST_NODE_LIST(error(tk,"missing comma in table",NULL),vals);
933 | }
934 | tk=consume();
935 | }
936 | }
937 | if(!tk){
938 | dealloc_list(keys);
939 | FREE_AST_NODE_LIST(error(tk,"unclosed table",NULL),vals);
940 | }
941 | return new_node(AST_TABLE,line,new_table_node(keys,vals));
942 | }
943 |
944 | // Primitive types parse functions
945 | AstNode* parse_string(){
946 | Token* tk=consume();
947 | if(!expect(tk,TK_QUOTE)) return error(tk,"invalid string",NULL);
948 | int line=tk->line;
949 | List* buffer=new_default_list();
950 | add_to_list(buffer,tk->text);
951 | Token* begin=tk;
952 | tk=consume_next();
953 | while(tk && !specific(tk,TK_QUOTE,begin->text)){
954 | add_to_list(buffer,tk->text);
955 | tk=consume_next();
956 | }
957 | if(tk) add_to_list(buffer,begin->text);
958 | else FREE_LIST(error(begin,"unclosed string",NULL),buffer);
959 | char* string=collapse_string_list(buffer);
960 | dealloc_list(buffer);
961 | AstNode* node=new_node(AST_PRIMITIVE,line,new_primitive_node(string,PRIMITIVE_STRING));
962 | free(string);
963 | return node;
964 | }
965 | AstNode* parse_number(){
966 | char dot[2]={'.',0};
967 | Token* tk=consume();
968 | if(!expect(tk,TK_INT)) return error(tk,"invalid number",NULL);
969 | Token* first=tk;
970 | tk=check_next();
971 | if(specific(tk,TK_MISC,".")){
972 | consume();
973 | tk=consume();
974 | if(!expect(tk,TK_INT)) return error(tk,"invalid floating point primitive",NULL);
975 | char* text=(char*)malloc(sizeof(char)*(strlen(first->text)+strlen(tk->text)+2));
976 | sprintf(text,"%s.%s",first->text,tk->text);
977 | return new_node(AST_PRIMITIVE,first->line,new_primitive_node(text,PRIMITIVE_FLOAT));
978 | }
979 | return new_node(AST_PRIMITIVE,first->line,new_primitive_node(first->text,PRIMITIVE_INT));
980 | }
981 | AstNode* parse_boolean(){
982 | Token* tk=consume();
983 | if(!expect(tk,TK_TRUE) && !expect(tk,TK_FALSE)) return error(tk,"invalid boolean primitive",NULL);
984 | return new_node(AST_PRIMITIVE,tk->line,new_primitive_node(tk->text,PRIMITIVE_BOOL));
985 | }
986 | AstNode* parse_nil(){
987 | Token* tk=consume();
988 | if(!expect(tk,TK_NIL)) return error(tk,"invalid nil",NULL);
989 | return new_node(AST_PRIMITIVE,tk->line,new_primitive_node("nil",PRIMITIVE_NIL));
990 | }
991 |
992 | // Expression parse functions
993 | AstNode* parse_tuple(){
994 | AstNode* node=parse_expr();
995 | if(!node) return NULL;
996 | int line=node->line;
997 | List* ls=new_default_list();
998 | add_to_list(ls,node);
999 | Token* tk=check();
1000 | while(specific(tk,TK_MISC,",")){
1001 | consume();
1002 | node=parse_expr();
1003 | if(!node) FREE_AST_NODE_LIST(NULL,ls);
1004 | add_to_list(ls,node);
1005 | tk=check();
1006 | }
1007 | return new_node(AST_TUPLE,line,new_ast_list_node(NULL,ls));
1008 | }
1009 | AstNode* parse_paren_or_tuple_function(){
1010 | int line;
1011 | Token* tk=check_ahead(2);
1012 | if(specific(tk,TK_BINARY,"*")){
1013 | AstNode* type=parse_type();
1014 | if(!type) return NULL;
1015 | line=type->line;
1016 | return parse_function(type,1);
1017 | }
1018 | if(expect(tk,TK_NAME)){
1019 | tk=check_ahead(3);
1020 | if(specific(tk,TK_MISC,",")){
1021 | AstNode* type=parse_type();
1022 | if(!type) return NULL;
1023 | line=type->line;
1024 | return parse_function(type,1);
1025 | }
1026 | }
1027 | tk=consume();
1028 | AstNode* node=parse_expr();
1029 | if(!node) return NULL;
1030 | tk=consume();
1031 | if(!specific(tk,TK_PAREN,")")) FREE_AST_NODE(error(tk,"unclosed expression",NULL),node);
1032 | return new_node(AST_PAREN,line,node);
1033 | }
1034 | static AstNode* precede_expr_tree(BinaryNode* data){
1035 | if(data->r->type!=AST_BINARY) return new_node(AST_BINARY,-1,data);
1036 | BinaryNode* r=(BinaryNode*)(data->r->data);
1037 | int lp=precedence(data->text);
1038 | int rp=precedence(r->text);
1039 | if(lp>rp){
1040 | AstNode* l=precede_expr_tree(new_binary_node(data->text,data->l,r->l));
1041 | return new_node(AST_BINARY,-1,new_binary_node(r->text,l,r->r));
1042 | }
1043 | return new_node(AST_BINARY,-1,data);
1044 | }
1045 | AstNode* parse_expr(){
1046 | Token* tk=check();
1047 | AstNode* node=NULL;
1048 | if(!tk) return error(tk,"incomplete expression",NULL);
1049 | if(tk->type==TK_NIL) node=parse_nil();
1050 | else if(expect(tk,TK_TRUE) || expect(tk,TK_FALSE)) node=parse_boolean();
1051 | else if(specific(tk,TK_PAREN,"(")) node=parse_paren_or_tuple_function();
1052 | else if(expect(tk,TK_FUNCTION)) node=parse_function(NULL,1);
1053 | else if(specific(tk,TK_CURLY,"{")) node=parse_table_or_list();
1054 | else if(expect(tk,TK_REQUIRE)) node=parse_require();
1055 | else if(expect(tk,TK_QUOTE)) node=parse_string();
1056 | else if(expect(tk,TK_SUPER)) node=parse_super();
1057 | else if(expect(tk,TK_INT)) node=parse_number();
1058 | else if(specific(tk,TK_BINARY,"*")){
1059 | AstNode* type=parse_type();
1060 | if(!type) return NULL;
1061 | node=parse_function(type,1);
1062 | }else if(tk->type==TK_NAME){
1063 | tk=check_ahead(2);
1064 | if(expect(tk,TK_FUNCTION)){
1065 | AstNode* type=parse_type();
1066 | if(!type) return NULL;
1067 | node=parse_function(type,1);
1068 | }else{
1069 | AstNode* lhs=parse_lhs();
1070 | if(lhs){
1071 | tk=check_next();
1072 | if(specific(tk,TK_PAREN,"(")) node=parse_call(lhs);
1073 | else node=lhs;
1074 | }
1075 | }
1076 | }else if(expect(tk,TK_UNARY) || specific(tk,TK_MISC,"-")){
1077 | char* text=consume()->text;
1078 | node=parse_expr();
1079 | if(!node) return NULL;
1080 | if(node->type==AST_BINARY){
1081 | BinaryNode* data=(BinaryNode*)(node->data);
1082 | if(precedence(data->text)l->type==AST_BINARY && precedence(((BinaryNode*)(data->l->data))->text)l->data);
1085 | }
1086 | data->l=new_node(AST_UNARY,node->line,new_unary_node(text,data->l));
1087 | }else node=new_node(AST_UNARY,node->line,new_unary_node(text,node));
1088 | }else node=new_node(AST_UNARY,node->line,new_unary_node(text,node));
1089 | }
1090 |
1091 | // Check for binary expressions
1092 | tk=check();
1093 | if(expect(tk,TK_BINARY) || specific(tk,TK_MISC,"-")){
1094 | char* op=tk->text;
1095 | AstNode* r;
1096 | consume();
1097 | if(!strcmp(op,"as")) r=parse_type();
1098 | else r=parse_expr();
1099 | if(!r) FREE_AST_NODE(NULL,node);
1100 | node=precede_expr_tree(new_binary_node(op,node,r));
1101 | }
1102 | if(!node) error(tk,"unexpected expression",NULL);
1103 | return node;
1104 | }
1105 |
--------------------------------------------------------------------------------
/src/scopes.c:
--------------------------------------------------------------------------------
1 | #include "./internal.h"
2 | #include
3 | #include
4 | #include
5 | static List* scopes; // List of Scopes
6 | static int first; // Flag to ensure we only register primitive types once
7 |
8 | /*
9 | Initialize a new scope object
10 | */
11 | static Scope* new_scope(int type,void* data){
12 | Scope* scope=(Scope*)malloc(sizeof(Scope));
13 | scope->interfaces_registry=new_default_list();
14 | scope->functions_registry=new_default_list();
15 | scope->classes_registry=new_default_list();
16 | scope->types_registry=new_default_list();
17 | scope->defs=new_default_list();
18 | scope->type=type;
19 | scope->data=data;
20 | return scope;
21 | }
22 |
23 | /*
24 | Stuff to be done before we start working with scopes
25 | */
26 | void preempt_scopes(){
27 | scopes=NULL;
28 | first=1;
29 | }
30 |
31 | /*
32 | Initializes the scope lists used by this module
33 | */
34 | void init_scopes(){
35 | scopes=new_default_list();
36 | }
37 |
38 | /*
39 | Deallocs all scope Lists
40 | */
41 | void dealloc_scopes(){
42 | dealloc_list(scopes);
43 | }
44 |
45 | /*
46 | Enters a new innermost scope
47 | */
48 | void push_scope(){
49 | add_to_list(scopes,new_scope(SCOPE_NONE,NULL));
50 | if(scopes->n==1){
51 | assert(first); // This can only happen once
52 | register_primitive(PRIMITIVE_STRING);
53 | register_primitive(PRIMITIVE_FLOAT);
54 | register_primitive(PRIMITIVE_BOOL);
55 | register_primitive(PRIMITIVE_INT);
56 | register_primitive(PRIMITIVE_NIL);
57 | first=0;
58 | }
59 | }
60 |
61 | /*
62 | Exits the current innermost scope
63 | */
64 | void pop_scope(){
65 | Scope* scope=remove_from_list(scopes,scopes->n-1);
66 | for(int a=0;adefs->n;a++){
67 | StringAstNode* var=(StringAstNode*)get_from_list(scope->defs,a);
68 | if(scope->type==SCOPE_CLASS && !strcmp(var->text,"this") && var->node->type==AST_TYPE_BASIC){
69 | ClassNode* class=(ClassNode*)(scope->data);
70 | char* type=(char*)(var->node->data);
71 | if(!strcmp(class->name,type)){
72 | free(var->text);
73 | free(var->node);
74 | }
75 | }
76 | free(var);
77 | }
78 | dealloc_list(scope->defs);
79 | for(int a=0;atypes_registry->n;a++){
80 | char* type=(char*)get_from_list(scope->types_registry,a);
81 | if(!strcmp(type,PRIMITIVE_STRING) || !strcmp(type,PRIMITIVE_FLOAT) || !strcmp(type,PRIMITIVE_BOOL) || !strcmp(type,PRIMITIVE_INT) || !strcmp(type,PRIMITIVE_NIL)){
82 | free(type);
83 | }
84 | }
85 | dealloc_list(scope->interfaces_registry);
86 | dealloc_list(scope->functions_registry);
87 | dealloc_list(scope->classes_registry);
88 | dealloc_list(scope->types_registry);
89 | free(scope);
90 | }
91 |
92 | /*
93 | Enters a new inner function scope
94 | */
95 | void push_function_scope(FunctionNode* node){
96 | add_to_list(scopes,new_scope(SCOPE_FUNCTION,node));
97 | for(int a=0;aargs->n;a++){
98 | StringAstNode* arg=(StringAstNode*)get_from_list(node->args,a);
99 | StringAstNode* var=new_string_ast_node(arg->text,arg->node);
100 | if(!add_scoped_var(var)){
101 | // This should never ever happen
102 | assert(0);
103 | free(var);
104 | }
105 | }
106 | }
107 |
108 | /*
109 | Returns the innermost function scope
110 | Returns NULL if the current scope is not within any function
111 | */
112 | FunctionNode* get_function_scope(){
113 | for(int a=scopes->n-1;a>=0;a--){
114 | Scope* scope=(Scope*)get_from_list(scopes,a);
115 | if(scope->type==SCOPE_FUNCTION){
116 | return (FunctionNode*)(scope->data);
117 | }
118 | }
119 | return NULL;
120 | }
121 |
122 | /*
123 | Returns the innermost class's method scope
124 | Returns NULL if the current scope is not within any class's method
125 | */
126 | FunctionNode* get_method_scope(){
127 | for(int a=scopes->n-1;a>=0;a--){
128 | Scope* scope=(Scope*)get_from_list(scopes,a);
129 | if(scope->type==SCOPE_FUNCTION && a){
130 | FunctionNode* func=(FunctionNode*)(scope->data);
131 | scope=(Scope*)get_from_list(scopes,a-1);
132 | if(scope->type==SCOPE_CLASS){
133 | return func;
134 | }
135 | }
136 | }
137 | return NULL;
138 | }
139 |
140 | /*
141 | Enters a new inner class scope
142 | */
143 | void push_class_scope(ClassNode* node){
144 | add_to_list(scopes,new_scope(SCOPE_CLASS,node));
145 | char* this=(char*)malloc(sizeof(char)*5);
146 | sprintf(this,"this");
147 | AstNode* type=new_node(AST_TYPE_BASIC,-1,node->name);
148 | StringAstNode* var=new_string_ast_node(this,type);
149 | if(!add_scoped_var(var)){
150 | // This should never ever happen
151 | assert(0);
152 | free(type);
153 | free(this);
154 | free(var);
155 | }
156 | }
157 |
158 | /*
159 | Returns the innermost class scope
160 | Returns NULL if the current scope is not within any class
161 | */
162 | ClassNode* get_class_scope(){
163 | for(int a=scopes->n-1;a>=0;a--){
164 | Scope* scope=(Scope*)get_from_list(scopes,a);
165 | if(scope->type==SCOPE_CLASS){
166 | return (ClassNode*)(scope->data);
167 | }
168 | }
169 | return NULL;
170 | }
171 |
172 | /*
173 | Adds a new typed variable to the current scope
174 | node must be allocated specifically for this function
175 | node will be freed automatically in pop_scope
176 | */
177 | int add_scoped_var(StringAstNode* node){
178 | Scope* scope=(Scope*)get_from_list(scopes,scopes->n-1);
179 | for(int a=0;adefs->n;a++){
180 | if(!strcmp(((StringAstNode*)get_from_list(scope->defs,a))->text,node->text)){
181 | return 0;
182 | }
183 | }
184 | add_to_list(scope->defs,node);
185 | return 1;
186 | }
187 |
188 | /*
189 | Returns the BinaryNode representing the typed variable called name
190 | Return NULL if no such typed variable exists
191 | Searches through every scope from innermost to outermost
192 | */
193 | StringAstNode* get_scoped_var(char* name){
194 | for(int a=(scopes->n)-1;a>=0;a--){
195 | Scope* scope=(Scope*)get_from_list(scopes,a);
196 | for(int b=0;bdefs->n;b++){
197 | StringAstNode* n=(StringAstNode*)get_from_list(scope->defs,b);
198 | if(!strcmp(n->text,name)){
199 | return n;
200 | }
201 | }
202 | }
203 | return NULL;
204 | }
205 |
206 | /*
207 | Returns 1 if the given field is defined as a class field
208 | */
209 | int field_defined_in_class(char* name){
210 | StringAstNode* node=get_scoped_var(name);
211 | for(int a=scopes->n-1;a>=0;a--){
212 | Scope* scope=(Scope*)get_from_list(scopes,a);
213 | for(int b=0;bdefs->n;b++){
214 | StringAstNode* n=(StringAstNode*)get_from_list(scope->defs,b);
215 | if(!strcmp(n->text,name)){
216 | return scope->type==SCOPE_CLASS;
217 | }
218 | }
219 | }
220 | return 0;
221 | }
222 |
223 | /*
224 | Returns the number of scopes
225 | */
226 | int get_num_scopes(){
227 | return scopes->n;
228 | }
229 |
230 | /*
231 | Returns the innermost scope
232 | */
233 | Scope* get_scope(){
234 | return (Scope*)get_from_list(scopes,scopes->n-1);
235 | }
236 |
237 | /*
238 | Registers a new primitive type (a typedef, class or interface)
239 | */
240 | void register_primitive(const char* name){
241 | Scope* scope=get_scope();
242 | char* type=(char*)malloc(sizeof(char)*(strlen(name)+1));
243 | strcpy(type,name);
244 | add_to_list(scope->types_registry,type);
245 | }
246 |
247 | /*
248 | Registers a type
249 | */
250 | void register_type(char* name){
251 | Scope* scope=get_scope();
252 | add_to_list(scope->types_registry,name);
253 | }
254 |
255 | /*
256 | Registers a function
257 | */
258 | void register_function(FunctionNode* node){
259 | Scope* scope=get_scope();
260 | add_to_list(scope->functions_registry,node);
261 | }
262 |
263 | /*
264 | Registers an interface
265 | */
266 | void register_interface(InterfaceNode* node){
267 | Scope* scope=get_scope();
268 | add_to_list(scope->interfaces_registry,node);
269 | }
270 |
271 | /*
272 | Registers a class
273 | */
274 | void register_class(ClassNode* node){
275 | Scope* scope=get_scope();
276 | add_to_list(scope->classes_registry,node);
277 | }
278 |
279 | /*
280 | Returns 1 if type name is registered
281 | */
282 | int type_exists(char* name){
283 | for(int a=scopes->n-1;a>=0;a--){
284 | Scope* scope=(Scope*)get_from_list(scopes,a);
285 | List* ls=scope->types_registry;
286 | for(int b=0;bn;b++){
287 | if(!strcmp((char*)get_from_list(ls,b),name)) return 1;
288 | }
289 | }
290 | return 0;
291 | }
292 |
293 | /*
294 | Returns the registered FunctionNode if name is a registered function
295 | Returns NULL if function name does not exist
296 | */
297 | FunctionNode* function_exists(char* name){
298 | if(!name) return NULL;
299 | for(int a=scopes->n-1;a>=0;a--){
300 | Scope* scope=(Scope*)get_from_list(scopes,a);
301 | List* ls=scope->functions_registry;
302 | for(int b=0;bn;b++){
303 | FunctionNode* node=(FunctionNode*)get_from_list(ls,b);
304 | assert(node->name->type==AST_ID); // I'm assuming func->name is of type AST_ID
305 | char* funcname=(char*)(node->name->data);
306 | if(node->name && !strcmp(name,funcname)){
307 | return node;
308 | }
309 | }
310 | }
311 | return NULL;
312 | }
313 |
314 | /*
315 | Returns the registered InterfaceNode if name is a registered interface
316 | Returns NULL if interface name does not exist
317 | */
318 | InterfaceNode* interface_exists(char* name){
319 | if(!name) return NULL;
320 | name=base_type(name);
321 | for(int a=scopes->n-1;a>=0;a--){
322 | Scope* scope=(Scope*)get_from_list(scopes,a);
323 | List* ls=scope->interfaces_registry;
324 | for(int b=0;bn;b++){
325 | InterfaceNode* node=(InterfaceNode*)get_from_list(ls,b);
326 | if(!strcmp(name,node->name)){
327 | return node;
328 | }
329 | }
330 | }
331 | return NULL;
332 | }
333 |
334 | /*
335 | Returns the registered ClassNode if name is a registered class
336 | Returns NULL if class name does not exist
337 | */
338 | ClassNode* class_exists(char* name){
339 | if(!name) return NULL;
340 | name=base_type(name);
341 | for(int a=scopes->n-1;a>=0;a--){
342 | Scope* scope=(Scope*)get_from_list(scopes,a);
343 | List* ls=scope->classes_registry;
344 | for(int b=0;bn;b++){
345 | ClassNode* node=(ClassNode*)get_from_list(ls,b);
346 | if(!strcmp(name,node->name)){
347 | return node;
348 | }
349 | }
350 | }
351 | return NULL;
352 | }
353 |
--------------------------------------------------------------------------------
/src/tokenizer.c:
--------------------------------------------------------------------------------
1 | #include "./internal.h"
2 | #include
3 | #include
4 | #include
5 | #define TOKEN_BUFFER_LENGTH 256 // Max length for a token string
6 | #define KEY_TOKEN(s,t) else if(!strcmp(buffer,s)) tk->type=t;
7 | #define SPECIAL_TOKEN(s,l,t) else if(n-a>=l && !strncmp(buffer+a,s,l)){ \
8 | tk->text=(char*)malloc(sizeof(char)*(l+1)); \
9 | sprintf(tk->text,s); \
10 | tk->type=t; \
11 | a+=l; \
12 | }
13 | static int class_alphanumeric=0; // Represents the alphanumeric token class
14 | static int class_whitespace=1; // Represents the whitespace token class
15 | static int class_special=2; // Represents the special token class
16 | static int multiline_comment=0; // Flag for tokenizing within a multiline comment
17 | static int comment=0; // Flag for tokenizing within a single line comment
18 |
19 | /*
20 | Get the character class for a char
21 | Helps detect boundaries for tokens
22 | */
23 | static int get_char_class(char c){
24 | if(c=='_' || ('a'<=c && c<='z') || ('A'<=c && c<='Z') || ('0'<=c && c<='9')) return class_alphanumeric;
25 | if(c==' ' || c=='\t' || c=='\n') return class_whitespace;
26 | return class_special;
27 | }
28 |
29 | /*
30 | Deallocate a token
31 | */
32 | void dealloc_token(Token* tk){
33 | free(tk->text);
34 | free(tk);
35 | }
36 |
37 | /*
38 | Generates tokens from a buffer of similarly-classes characters
39 | */
40 | static void discover_tokens(List* ls,int line,char* buffer,int n,int char_class){
41 | buffer[n]=0;
42 | if(char_class!=class_special){
43 |
44 | // Comment tokenization
45 | if(comment && char_class==class_whitespace){
46 | for(int a=0;atext=(char*)malloc(sizeof(char)*(n+1));
56 | strcpy(tk->text,buffer);
57 | add_to_list(ls,tk);
58 | tk->line=line;
59 | if(char_class==class_whitespace) tk->type=TK_SPACE;
60 | else{
61 | if(!strcmp(buffer,"and")) tk->type=TK_BINARY;
62 | KEY_TOKEN("constructor",TK_CONSTRUCTOR)
63 | KEY_TOKEN("implements",TK_IMPLEMENTS)
64 | KEY_TOKEN("interface",TK_INTERFACE)
65 | KEY_TOKEN("function",TK_FUNCTION)
66 | KEY_TOKEN("extends",TK_EXTENDS)
67 | KEY_TOKEN("require",TK_REQUIRE)
68 | KEY_TOKEN("typedef",TK_TYPEDEF)
69 | KEY_TOKEN("elseif",TK_ELSEIF)
70 | KEY_TOKEN("repeat",TK_REPEAT)
71 | KEY_TOKEN("return",TK_RETURN)
72 | KEY_TOKEN("local",TK_LOCAL)
73 | KEY_TOKEN("break",TK_BREAK)
74 | KEY_TOKEN("false",TK_FALSE)
75 | KEY_TOKEN("class",TK_CLASS)
76 | KEY_TOKEN("where",TK_WHERE)
77 | KEY_TOKEN("trust",TK_UNARY)
78 | KEY_TOKEN("super",TK_SUPER)
79 | KEY_TOKEN("until",TK_UNTIL)
80 | KEY_TOKEN("while",TK_WHILE)
81 | KEY_TOKEN("final",TK_FINAL)
82 | KEY_TOKEN("then",TK_THEN)
83 | KEY_TOKEN("true",TK_TRUE)
84 | KEY_TOKEN("goto",TK_GOTO)
85 | KEY_TOKEN("not",TK_UNARY)
86 | KEY_TOKEN("or",TK_BINARY)
87 | KEY_TOKEN("as",TK_BINARY)
88 | KEY_TOKEN("else",TK_ELSE)
89 | KEY_TOKEN("new",TK_NEW)
90 | KEY_TOKEN("var",TK_VAR)
91 | KEY_TOKEN("end",TK_END)
92 | KEY_TOKEN("for",TK_FOR)
93 | KEY_TOKEN("nil",TK_NIL)
94 | KEY_TOKEN("do",TK_DO)
95 | KEY_TOKEN("if",TK_IF)
96 | KEY_TOKEN("in",TK_IN)
97 | else{
98 | tk->type=TK_INT;
99 | for(int a=0;a'9'){
101 | tk->type=TK_NAME;
102 | break;
103 | }
104 | }
105 | }
106 | }
107 | }else{ // Special class tokenization
108 | int a=0;
109 | while(a=2 && !strncmp(buffer+a,"]]",2)){
112 | multiline_comment=0;
113 | a++;
114 | }
115 | a++;
116 | continue;
117 | }
118 | if(comment) break;
119 | if(n-a>=4 && !strncmp(buffer+a,"--[[",4)){
120 | multiline_comment=1;
121 | a+=4;
122 | continue;
123 | }
124 | if(n-a>=2 && !strncmp(buffer+a,"--",2)){
125 | comment=1;
126 | break;
127 | }
128 | Token* tk=(Token*)malloc(sizeof(Token));
129 | tk->text=NULL;
130 | tk->line=line;
131 | if(n-a>=3 && !strncmp(buffer+a,"...",3)){
132 | tk->text=(char*)malloc(sizeof(char)*4);
133 | sprintf(tk->text,"...");
134 | tk->type=TK_DOTS;
135 | a+=3;
136 | }
137 | SPECIAL_TOKEN("..",2,TK_BINARY)
138 | SPECIAL_TOKEN("<=",2,TK_BINARY)
139 | SPECIAL_TOKEN(">=",2,TK_BINARY)
140 | SPECIAL_TOKEN("==",2,TK_BINARY)
141 | SPECIAL_TOKEN("~=",2,TK_BINARY)
142 | SPECIAL_TOKEN("::",2,TK_DBCOLON)
143 | SPECIAL_TOKEN("<",1,TK_BINARY)
144 | SPECIAL_TOKEN(">",1,TK_BINARY)
145 | SPECIAL_TOKEN("+",1,TK_BINARY)
146 | SPECIAL_TOKEN("^",1,TK_BINARY)
147 | SPECIAL_TOKEN("*",1,TK_BINARY)
148 | SPECIAL_TOKEN("/",1,TK_BINARY)
149 | SPECIAL_TOKEN("#",1,TK_UNARY)
150 | SPECIAL_TOKEN("'",1,TK_QUOTE)
151 | SPECIAL_TOKEN("\"",1,TK_QUOTE)
152 | SPECIAL_TOKEN("(",1,TK_PAREN)
153 | SPECIAL_TOKEN(")",1,TK_PAREN)
154 | SPECIAL_TOKEN("{",1,TK_CURLY)
155 | SPECIAL_TOKEN("}",1,TK_CURLY)
156 | SPECIAL_TOKEN("[",1,TK_SQUARE)
157 | SPECIAL_TOKEN("]",1,TK_SQUARE)
158 | else{
159 | tk->text=(char*)malloc(sizeof(char)*2);
160 | tk->text[0]=buffer[a];
161 | tk->type=TK_MISC;
162 | tk->text[1]=0;
163 | a++;
164 | }
165 | add_to_list(ls,tk);
166 | }
167 | }
168 | }
169 |
170 | /*
171 | Read through some Lua code and tokenize it along the way
172 | Returns a list of Tokens
173 | */
174 | List* tokenize(FILE* f){
175 | int line=1;
176 | if(!f) return NULL;
177 | int current_class=-1;
178 | List* ls=new_list(100);
179 | char buffer[TOKEN_BUFFER_LENGTH];
180 | int i=0;
181 | while(1){
182 | char c=fgetc(f);
183 | if(feof(f)){
184 | if(i) discover_tokens(ls,line,buffer,i,current_class);
185 | break;
186 | }
187 | int char_class=get_char_class(c);
188 | if(current_class!=-1 && char_class!=current_class){
189 | discover_tokens(ls,line,buffer,i,current_class);
190 | i=0;
191 | }
192 | current_class=char_class;
193 | if(c=='\n') line++;
194 | if(i==TOKEN_BUFFER_LENGTH){
195 | for(int a=0;an;a++) dealloc_token((Token*)get_from_list(ls,a));
196 | dealloc_list(ls);
197 | return NULL;
198 | }
199 | buffer[i++]=c;
200 | }
201 | return ls;
202 | }
203 |
--------------------------------------------------------------------------------
/src/traversal.c:
--------------------------------------------------------------------------------
1 | #include "./internal.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #define ERROR(cond,line,msg,...) if(cond){assert(step!=STEP_OUTPUT);add_error(line,msg,__VA_ARGS__);return;}
8 | static char* instance_str; // The variable used for the produced object in constructors
9 | static FILE* _output; // The configured output as desired by the developer
10 | static int step; // The traversal step you're currently processing
11 | static int num_indents; // Number of tabs on the output line
12 | static AstNode* float_type; // AstNode constant representing the FLOAT type
13 | static AstNode* bool_type; // AstNode constant representing the BOOL type
14 | static AstNode* int_type; // AstNode constant representing the INT type
15 | static AstNode* any_type; // AstNode constant representing the ANY type
16 |
17 | /*
18 | The traversal step of this compiler has 4 phases:
19 | typedef, relate, check, output
20 | The typedef phase is when we traverse through a scope (an AST subtree) and register the types defined there
21 | The relate phase is where we go through each type and register any equivalencies (since the types need to exist first)
22 | The check phase is when we perform general compile-time checks
23 | The output phase happen after all checks have been performed, this is when we write Lua code to output
24 | */
25 |
26 | // Get number of indents
27 | int get_num_indents(){
28 | return num_indents;
29 | }
30 |
31 | // Constant primitive type AstNodes access
32 | AstNode* float_type_const(){
33 | return float_type;
34 | }
35 | AstNode* bool_type_const(){
36 | return bool_type;
37 | }
38 | AstNode* int_type_const(){
39 | return int_type;
40 | }
41 | AstNode* any_type_const(){
42 | return any_type;
43 | }
44 |
45 | /*
46 | Set up resources used by traversal
47 | */
48 | void init_traverse(){
49 | instance_str=(char*)malloc(sizeof(char)*6);
50 | float_type=new_node(AST_TYPE_BASIC,-1,PRIMITIVE_FLOAT);
51 | bool_type=new_node(AST_TYPE_BASIC,-1,PRIMITIVE_BOOL);
52 | int_type=new_node(AST_TYPE_BASIC,-1,PRIMITIVE_INT);
53 | any_type=new_node(AST_TYPE_ANY,-1,NULL);
54 | sprintf(instance_str,"__obj");
55 | num_indents=0;
56 | preempt_scopes();
57 | init_types();
58 | init_scopes();
59 | push_scope();
60 | }
61 |
62 | /*
63 | Traverse through a parsed Moonshot AST
64 | This function is called twice in the Moonshot compile function
65 | */
66 | void traverse(AstNode* root,int initial_step){
67 | step=initial_step;
68 | process_node_list((List*)(root->data));
69 | }
70 |
71 | /*
72 | Deallocate resources used by the traversal module
73 | */
74 | void dealloc_traverse(){
75 | free(instance_str);
76 | pop_scope();
77 | assert(get_num_scopes()==0);
78 | dealloc_scopes();
79 | dealloc_types();
80 | free(any_type);
81 | free(int_type);
82 | free(bool_type);
83 | free(float_type);
84 | }
85 |
86 | /*
87 | Sets the output to the stream desired by the developer
88 | */
89 | void set_output(FILE* output){
90 | _output=output;
91 | }
92 |
93 | /*
94 | Increment the output indentation
95 | */
96 | static void indent(int a){
97 | if(step==STEP_OUTPUT){
98 | num_indents+=a;
99 | }
100 | }
101 |
102 | /*
103 | Writes a message to the configured output
104 | */
105 | static void write(const char* msg,...){
106 | if(step==STEP_OUTPUT){
107 | va_list args;
108 | va_start(args,msg);
109 | char* str=format_string(1,msg,args);
110 | fprintf(_output,"%s",str);
111 | free(str);
112 | va_end(args);
113 | }
114 | }
115 |
116 | /*
117 | Prints a newline character after nodes that could either be a value or statement
118 | */
119 | static void conditional_newline(AstNode* node){
120 | if(step==STEP_OUTPUT){
121 | if(node->type==AST_FUNCTION) write("\n");
122 | if(node->type==AST_CALL) write("\n");
123 | if(node->type==AST_REQUIRE){
124 | AstNode* data=(AstNode*)(node->data);
125 | assert(data->type==AST_PRIMITIVE); // data is AST_PRIMITIVE with type string
126 | StringAstNode* primitive=(StringAstNode*)(data->data);
127 | char* filename=primitive->text;
128 | int l=strlen(filename);
129 |
130 | // Only needs a newline if we're NOT requiring another Moonshot file
131 | // Moonshot requires disappear, we don't want a random empty line
132 | if(l>=6 && strncmp(filename+l-6,".moon",5)){
133 | write("\n");
134 | }
135 | }
136 | }
137 | }
138 |
139 | /*
140 | Canonical traversal method structure:
141 | if step==STEP_TYPEDEF
142 | do your typedef step
143 | else if step==STEP_RELATE
144 | do your relate step
145 | else
146 | push scope
147 | do your check and output steps
148 | pop scope
149 | end
150 | */
151 |
152 | /*
153 | Process a list of AstNodes
154 | Usually called once for each scope
155 | */
156 | void process_node_list(List* ls){
157 | if(step==STEP_CHECK){
158 | // We need to load up scoped types before we can check this scope
159 | step=STEP_TYPEDEF;
160 | for(int a=0;an;a++) process_node((AstNode*)get_from_list(ls,a));
161 |
162 | step=STEP_RELATE;
163 | for(int a=0;an;a++) process_node((AstNode*)get_from_list(ls,a));
164 |
165 | step=STEP_CHECK;
166 | for(int a=0;an;a++) process_node((AstNode*)get_from_list(ls,a));
167 | quell_expired_scope_equivalences(get_num_scopes());
168 | }
169 | if(step==STEP_OUTPUT){
170 | for(int a=0;an;a++){
171 | AstNode* e=(AstNode*)get_from_list(ls,a);
172 | process_node(e);
173 | conditional_newline(e);
174 | }
175 | }
176 | }
177 |
178 | /*
179 | Switch for calling a specific traversal method by AstNode type
180 | */
181 | void process_node(AstNode* node){
182 | switch(node->type){
183 | case AST_STMT: process_node_list((List*)(node->data)); return;
184 | case AST_LIST: process_list_primitive_node(node); return;
185 | case AST_PRIMITIVE: process_primitive(node); return;
186 | case AST_INTERFACE: process_interface(node); return;
187 | case AST_FUNCTION: process_function(node); return;
188 | case AST_TYPEDEF: process_typedef(node); return;
189 | case AST_REQUIRE: process_require(node); return;
190 | case AST_DEFINE: process_define(node); return;
191 | case AST_REPEAT: process_repeat(node); return;
192 | case AST_LTUPLE: process_ltuple(node); return;
193 | case AST_RETURN: process_return(node); return;
194 | case AST_BINARY: process_binary(node); return;
195 | case AST_FORNUM: process_fornum(node); return;
196 | case AST_ELSEIF: process_elseif(node); return;
197 | case AST_CLASS: process_class(node); return;
198 | case AST_SUPER: process_super(node); return;
199 | case AST_BREAK: process_break(node); return;
200 | case AST_FORIN: process_forin(node); return;
201 | case AST_PAREN: process_paren(node); return;
202 | case AST_UNARY: process_unary(node); return;
203 | case AST_TUPLE: process_tuple(node); return;
204 | case AST_TABLE: process_table(node); return;
205 | case AST_LOCAL: process_local(node); return;
206 | case AST_WHILE: process_while(node); return;
207 | case AST_FIELD: process_field(node); return;
208 | case AST_LABEL: process_label(node); return;
209 | case AST_GOTO: process_goto(node); return;
210 | case AST_CALL: process_call(node); return;
211 | case AST_ELSE: process_else(node); return;
212 | case AST_SET: process_set(node); return;
213 | case AST_SUB: process_sub(node); return;
214 | case AST_IF: process_if(node); return;
215 | case AST_DO: process_do(node); return;
216 | case AST_ID: process_id(node); return;
217 | default: add_error(node->line,"invalid Moonshot AST detected (node ID %i)",node->type);
218 | }
219 | }
220 |
221 | /*
222 | Traverses through entity nodes
223 | */
224 | void process_interface(AstNode* node){
225 | InterfaceNode* data=(InterfaceNode*)(node->data);
226 | if(step==STEP_TYPEDEF){
227 | ERROR(type_exists(data->name),node->line,"type %s is already declared",data->name);
228 | register_type(data->name);
229 | register_interface(data);
230 | }
231 | if(step==STEP_RELATE){
232 | if(data->parent){
233 | ERROR(!interface_exists(data->parent),node->line,"parent interface %s does not exist",data->parent);
234 | ERROR(!add_child_type(data->name,data->parent,RL_EXTENDS),node->line,"co-dependent interface %s detected",data->name);
235 | }
236 | }
237 | }
238 | void process_class(AstNode* node){
239 | ClassNode* data=(ClassNode*)(node->data);
240 | if(step==STEP_TYPEDEF){
241 | ERROR(type_exists(data->name),node->line,"type %s is already declared",data->name);
242 | register_type(data->name);
243 | register_class(data);
244 | }else if(step==STEP_RELATE){
245 | if(data->parent){
246 | ERROR(!class_exists(data->parent),node->line,"parent class %s does not exist",data->parent);
247 | ERROR(!add_child_type(data->name,data->parent,RL_EXTENDS),node->line,"co-dependent class %s detected",data->name);
248 | }
249 | for(int a=0;ainterfaces->n;a++){
250 | char* interface=(char*)get_from_list(data->interfaces,a);
251 | ERROR(!interface_exists(interface),node->line,"interface %s does not exist",interface);
252 | add_child_type(data->name,interface,RL_IMPLEMENTS);
253 | }
254 | }else{
255 | push_class_scope(data);
256 | if(step==STEP_CHECK){
257 |
258 | // Check constructors
259 | int num_cons=num_constructors(data);
260 | ERROR(num_cons>1,node->line,"class %s has %i constructors, should have only 1",data->name,num_cons);
261 |
262 | // Check unimplemented methods
263 | List* missing=get_missing_class_methods(data);
264 | if(missing->n){
265 | for(int a=0;an;a++){
266 | FunctionNode* f=(FunctionNode*)get_from_list(missing,a);
267 | add_error(node->line,"Class %s does not implement method %s",data->name,(char*)(f->name->data));
268 | }
269 | }
270 | dealloc_list(missing);
271 | }
272 | List* all_fields=get_all_class_fields(data);
273 | Map* fields=collapse_ancestor_class_fields(all_fields);
274 | dealloc_list(all_fields);
275 | ERROR(step==STEP_CHECK && !fields,node->line,"class %s has colliding names",data->name);
276 | write("function %s(",data->name);
277 | FunctionNode* fdata=get_constructor(data);
278 | if(fdata){
279 | for(int a=0;aargs->n;a++){
280 | StringAstNode* e=(StringAstNode*)get_from_list(fdata->args,a);
281 | if(a) write(",");
282 | write("%s",e->text);
283 | }
284 | }
285 | write(")\n");
286 | indent(1);
287 | write("local %s={}\n",instance_str);
288 | if(fields){
289 | for(int a=0;an;a++){
290 | AstNode* child=(AstNode*)iterate_from_map(fields,a);
291 | if(child->type==AST_DEFINE){
292 | BinaryNode* cdata=(BinaryNode*)(child->data);
293 | add_scoped_var(new_string_ast_node(cdata->text,cdata->l));
294 | if(cdata->r){
295 | write("%s.%s=",instance_str,cdata->text);
296 | process_node(cdata->r);
297 | }else{
298 | write("%s.%s=nil",instance_str,cdata->text);
299 | }
300 | write("\n");
301 | }
302 | }
303 | }
304 | if(fdata){
305 | push_function_scope(fdata);
306 | process_node_list(fdata->body);
307 | pop_scope();
308 | }
309 | if(fields){
310 | for(int a=0;an;a++){
311 | AstNode* child=(AstNode*)iterate_from_map(fields,a);
312 | if(child->type==AST_FUNCTION){
313 | fdata=(FunctionNode*)(child->data);
314 | if(fdata->is_constructor) continue;
315 | push_function_scope(fdata);
316 | char* funcname=(char*)(fdata->name->data);
317 | //add_scoped_var(new_string_ast_node(funcname,get_type(child)));
318 | write("%s.%s=function(",instance_str,funcname);
319 | if(fdata->args){
320 | for(int a=0;aargs->n;a++){
321 | if(a) write(",");
322 | char* arg=((StringAstNode*)get_from_list(fdata->args,a))->text;
323 | write("%s",arg);
324 | }
325 | }
326 | write(")\n");
327 | indent(1);
328 | process_node_list(fdata->body);
329 | indent(-1);
330 | write("end\n");
331 | pop_scope();
332 | }else if(child->type!=AST_DEFINE){
333 | add_error(child->line,"invalid child node in class %s",data->name);
334 | break;
335 | }
336 | }
337 | dealloc_map(fields);
338 | }
339 | write("return %s\n",instance_str);
340 | indent(-1);
341 | write("end\n");
342 | pop_scope();
343 | }
344 | }
345 |
346 | /*
347 | Traverses through node groups
348 | */
349 | void process_do(AstNode* node){
350 | if(step==STEP_CHECK || step==STEP_OUTPUT){
351 | push_scope();
352 | write("do\n");
353 | indent(1);
354 | process_node_list((List*)(node->data));
355 | indent(-1);
356 | write("end\n");
357 | pop_scope();
358 | }
359 | }
360 |
361 | /*
362 | Returns 1 if the provided arguments can be accepted by the function definition
363 | target is whatever entity you want represented in any potential error messages
364 | func is the AST_FUNCTION node you're calling
365 | args_node is the AST_TUPLE node that represents your arguments
366 | */
367 | static int validate_function_parameters(char* target,AstNode* func,AstNode* args_node){
368 | if(!func){
369 | if(args_node){
370 | List* args=((AstListNode*)(args_node->data))->list;
371 | return args->n==0;
372 | }
373 | return 1;
374 | }
375 | AstNode* functype=get_type(func);
376 | List* funcargs=functype->data?((AstListNode*)(functype->data))->list:NULL;
377 | if(args_node){
378 | List* args=((AstListNode*)(args_node->data))->list;
379 | if(!funcargs){
380 | add_error(func->line,"too many arguments for %s",target);
381 | return 0;
382 | }
383 | int max=funcargs->n;
384 | if(is_variadic_function(funcargs)){
385 | if(args->nn-1){
386 | add_error(func->line,"not enough arguments for %s",target);
387 | return 0;
388 | }
389 | max=funcargs->n-1;
390 | }else if(args->n!=funcargs->n){
391 | add_error(func->line,"invalid number of arguments for %s",target);
392 | return 0;
393 | }
394 | for(int a=0;aline,"invalid argument provided for %s",target);
399 | return 0;
400 | }
401 | }
402 | }else if(funcargs && funcargs->n && !(funcargs->n==1 && is_variadic_function(funcargs))){
403 | add_error(func->line,"not enough arguments for %s",target);
404 | return 0;
405 | }
406 | return 1;
407 | }
408 |
409 | /*
410 | Traverses through function call nodes
411 | */
412 | void process_call(AstNode* node){
413 | AstAstNode* data=(AstAstNode*)(node->data);
414 | if(step==STEP_CHECK || step==STEP_OUTPUT){
415 | if(step==STEP_CHECK){
416 | char* name=NULL;
417 | AstNode* functype=NULL;
418 | AstNode* funcnode=NULL;
419 | FunctionNode* func=NULL;
420 | AstNode* dummy_constructor_type=NULL;
421 | if(data->l->type==AST_ID){
422 | name=(char*)(data->l->data);
423 | func=function_exists(name);
424 | if(func){
425 | funcnode=new_node(AST_FUNCTION,-1,func);
426 | functype=get_type(funcnode);
427 | }else{
428 | ClassNode* clas=class_exists(name);
429 | if(clas){
430 | FunctionNode* constructor=get_constructor(clas);
431 | if(constructor){
432 | funcnode=new_node(AST_FUNCTION,-1,constructor);
433 | functype=get_type(funcnode);
434 | }else{
435 | dummy_constructor_type=new_node(AST_TYPE_FUNC,-1,new_ast_list_node(new_node(AST_TYPE_BASIC,-1,name),new_default_list()));
436 | functype=dummy_constructor_type;
437 | }
438 | }
439 | }
440 | }else if(data->l->type==AST_FIELD){
441 | name=((StringAstNode*)(data->l->data))->text;
442 | functype=get_type(data->l);
443 | }
444 | if(functype){
445 | char* target=(char*)malloc(sizeof(char)*(strlen(name)+10));
446 | sprintf(target,"function %s",name);
447 | validate_function_parameters(target,funcnode,data->r);
448 | if(dummy_constructor_type){
449 | dealloc_ast_type(dummy_constructor_type);
450 | }
451 | if(funcnode) free(funcnode);
452 | free(target);
453 | }
454 | }
455 | process_node(data->l);
456 | write("(");
457 | if(data->r) process_node(data->r);
458 | write(")");
459 | }
460 | }
461 | void process_super(AstNode* node){
462 | if(step==STEP_CHECK || step==STEP_OUTPUT){
463 | AstNode* data=(AstNode*)(node->data);
464 | ClassNode* clas=get_class_scope();
465 | FunctionNode* func=get_method_scope();
466 | if(step==STEP_CHECK){
467 | ERROR(!clas,node->line,"cannot use super methods outside of a class",NULL);
468 | ERROR(!func,node->line,"must use super keyword within a class method",NULL);
469 | ERROR(!clas->parent,node->line,"cannot use super methods because %s is not a child class",clas->name);
470 | }
471 | ClassNode* parent=class_exists(clas->parent);
472 | FunctionNode* method=get_parent_method(parent,func);
473 | if(step==STEP_CHECK){
474 | if(!func->is_constructor){
475 | assert(func->name->type==AST_ID); // I'm assuming func->name is of type AST_ID
476 | }
477 | ERROR(!method && func->is_constructor,node->line,"constructor in class %s does not override a super constructor",clas->name);
478 | ERROR(!method && !func->is_constructor,node->line,"method %s in class %s does not override a super method",(char*)(func->name->data),clas->name);
479 | char* target=(char*)malloc(sizeof(char)*(strlen(parent->name)+22));
480 | sprintf(target,"constructor of class %s",parent->name);
481 | AstNode* fnode=new_node(AST_FUNCTION,-1,method);
482 | validate_function_parameters(target,fnode,data);
483 | free(target);
484 | free(fnode);
485 | }
486 | push_class_scope(parent);
487 | push_function_scope(method);
488 | write("(function(");
489 | for(int a=0;aargs->n;a++){
490 | StringAstNode* e=(StringAstNode*)get_from_list(method->args,a);
491 | if(a) write(",");
492 | write("%s",e->text);
493 | }
494 | write(")\n");
495 | indent(1);
496 | for(int a=0;abody->n;a++){
497 | AstNode* child=(AstNode*)get_from_list(method->body,a);
498 | process_node(child);
499 | conditional_newline(child);
500 | }
501 | indent(-1);
502 | write("end)(");
503 | if(data){
504 | List* args=((AstListNode*)(data->data))->list;
505 | for(int a=0;an;a++){
506 | if(a) write(",");
507 | process_node((AstNode*)get_from_list(args,a));
508 | }
509 | }
510 | write(")\n");
511 | pop_scope();
512 | pop_scope();
513 | }
514 | }
515 |
516 | /*
517 | Traverses through miscellaneous value nodes
518 | */
519 | void process_set(AstNode* node){
520 | AstAstNode* data=(AstAstNode*)(node->data);
521 | if(step==STEP_CHECK || step==STEP_OUTPUT){
522 | if(step==STEP_CHECK){
523 | AstNode* tl=get_type(data->l);
524 | AstNode* tr=get_type(data->r);
525 | if(tr->type==AST_TYPE_TUPLE){
526 | List* ls=(List*)(tr->data);
527 | if(ls->n==1) tr=(AstNode*)get_from_list(ls,0);
528 | }
529 | ERROR(!typed_match(tl,tr),node->line,"expression of type %t cannot be assigned to variable of type %t",tr,tl);
530 | }
531 | process_node(data->l);
532 | write("=");
533 | process_node(data->r);
534 | write("\n");
535 | }
536 | }
537 | void process_return(AstNode* node){
538 | if(step==STEP_CHECK || step==STEP_OUTPUT){
539 | if(step==STEP_CHECK){
540 | FunctionNode* func=get_function_scope();
541 | if(func){
542 | AstNode* type1=func->type;
543 | AstNode* type2=node->data?get_type(node->data):any_type_const();
544 | if(type2->type==AST_TYPE_TUPLE){
545 | List* ls=(List*)(type2->data);
546 | if(ls->n==1){
547 | type2=(AstNode*)get_from_list(ls,0);
548 | }
549 | }
550 | ERROR(!typed_match(type1,type2),node->line,"function of type %t cannot return type %t",type1,type2);
551 | }
552 | }
553 | write("return");
554 | if(node->data){
555 | write(" ");
556 | process_node((AstNode*)(node->data));
557 | }
558 | write("\n");
559 | }
560 | }
561 |
562 | /*
563 | Traverses through identifier nodes
564 | */
565 | void process_ltuple(AstNode* node){
566 | if(step==STEP_CHECK || step==STEP_OUTPUT){
567 | AstListNode* data=(AstListNode*)(node->data);
568 | for(int a=0;alist->n;a++){
569 | if(a) write(",");
570 | process_id((AstNode*)get_from_list(data->list,a));
571 | }
572 | }
573 | }
574 | void process_field(AstNode* node){
575 | if(step==STEP_CHECK || step==STEP_OUTPUT){
576 | StringAstNode* data=(StringAstNode*)(node->data);
577 | process_node(data->node);
578 | write(".%s",data->text);
579 | }
580 | }
581 | void process_sub(AstNode* node){
582 | if(step==STEP_CHECK || step==STEP_OUTPUT){
583 | AstAstNode* data=(AstAstNode*)(node->data);
584 | process_node(data->l);
585 | write("[");
586 | process_node(data->r);
587 | write("]");
588 | }
589 | }
590 | void process_id(AstNode* node){
591 | if(step==STEP_OUTPUT){
592 | char* var=(char*)(node->data);
593 | if(get_class_scope() && !strcmp(var,"this")){
594 | write("%s",instance_str);
595 | }else{
596 | if(field_defined_in_class(var)){
597 | write("%s.",instance_str);
598 | }
599 | write("%s",var);
600 | }
601 | }
602 | }
603 |
604 | /*
605 | Traverses through nodes that define new things
606 | */
607 | void process_require(AstNode* node){
608 | AstNode* data=(AstNode*)(node->data);
609 | assert(data->type==AST_PRIMITIVE); // data is AST_PRIMITIVE with type string
610 | StringAstNode* primitive=(StringAstNode*)(data->data);
611 | if(!require_file(primitive->text,step)){
612 | write("require %s",primitive->text);
613 | }
614 | }
615 | void process_local(AstNode* node){
616 | if(step==STEP_CHECK || step==STEP_OUTPUT){
617 | StringAstNode* data=(StringAstNode*)(node->data);
618 | write("local %s",data->text);
619 | if(data->node){
620 | write("=");
621 | process_node(data->node);
622 | }
623 | write("\n");
624 | }
625 | }
626 | void process_define(AstNode* node){
627 | if(step==STEP_CHECK || step==STEP_OUTPUT){
628 | BinaryNode* data=(BinaryNode*)(node->data);
629 | if(step==STEP_CHECK){
630 | ERROR(!compound_type_exists(data->l),node->line,"reference to nonexistent type %t",data->l);
631 | if(data->r){
632 | AstNode* tr=get_type(data->r);
633 | ERROR(!typed_match(data->l,tr),node->line,"expression of type %t cannot be assigned to variable of type %t",tr,data->l);
634 | }
635 | StringAstNode* data1=new_string_ast_node(data->text,data->l);
636 | if(!add_scoped_var(data1)){
637 | add_error(node->line,"variable %s was already declared in this scope",data->text);
638 | free(data1);
639 | }
640 | }
641 | if(get_num_scopes()>1) write("local ");
642 | write("%s=",data->text);
643 | if(data->r) process_node(data->r);
644 | else write("nil");
645 | write("\n");
646 | }
647 | }
648 | void process_typedef(AstNode* node){
649 | StringAstNode* data=(StringAstNode*)(node->data);
650 | if(step==STEP_TYPEDEF){
651 | ERROR(type_exists(data->text),node->line,"type %s is already declared",data->text);
652 | register_type(data->text);
653 | }else if(step==STEP_RELATE){
654 | ERROR(!compound_type_exists(data->node),node->line,"type %t does not exist",data->node);
655 | ERROR(!add_type_equivalence(data->text,data->node,RL_EQUALS),node->line,"co-dependent typedef %s detected",data->text);
656 | }
657 | }
658 |
659 | /*
660 | Traverses through a function node
661 | */
662 | void process_function(AstNode* node){
663 | if(step==STEP_CHECK || step==STEP_OUTPUT){
664 | FunctionNode* data=(FunctionNode*)(node->data);
665 | write("function");
666 | if(data->name){
667 | if(data->type) register_function(data);
668 | write(" ");
669 | process_node(data->name);
670 | }
671 | write("(");
672 | for(int a=0;aargs->n;a++){
673 | if(a) write(",");
674 | StringAstNode* e=(StringAstNode*)get_from_list(data->args,a);
675 | ERROR(!compound_type_exists(e->node),node->line,"reference to nonexistent type %t",e->node);
676 | write("%s",e->text);
677 | }
678 | write(")\n");
679 | indent(1);
680 | if(data->body){
681 | push_function_scope(data);
682 | int num_returns=0;
683 | for(int a=0;abody->n;a++){
684 | AstNode* child=(AstNode*)get_from_list(data->body,a);
685 | if(child->type==AST_RETURN) num_returns++;
686 | process_node(child);
687 | conditional_newline(child);
688 | }
689 | if(data->is_constructor){
690 | ERROR(num_returns,node->line,"constructors cannot have return statements",NULL);
691 | }else if(!is_primitive(data->type,PRIMITIVE_NIL) && data->type->type!=AST_TYPE_ANY){
692 | ERROR(!num_returns,node->line,"function of type %t cannot return nil",data->type);
693 | }
694 | indent(-1);
695 | write("end");
696 | pop_scope();
697 | }
698 | }
699 | }
700 |
701 | /*
702 | Traverses through conditional nodes
703 | */
704 | void process_repeat(AstNode* node){
705 | if(step==STEP_CHECK || step==STEP_OUTPUT){
706 | AstListNode* data=(AstListNode*)(node->data);
707 | write("repeat\n");
708 | indent(1);
709 | push_scope();
710 | process_node_list(data->list);
711 | pop_scope();
712 | indent(-1);
713 | write("until ");
714 | process_node(data->node);
715 | write("\n");
716 | }
717 | }
718 | void process_while(AstNode* node){
719 | if(step==STEP_CHECK || step==STEP_OUTPUT){
720 | AstListNode* data=(AstListNode*)(node->data);
721 | write("while ");
722 | process_node(data->node);
723 | write(" do\n");
724 | indent(1);
725 | push_scope();
726 | process_node_list(data->list);
727 | pop_scope();
728 | indent(-1);
729 | write("end\n");
730 | }
731 | }
732 | void process_if(AstNode* node){
733 | if(step==STEP_CHECK || step==STEP_OUTPUT){
734 | IfNode* data=(IfNode*)(node->data);
735 | write("if ");
736 | process_node(data->expr);
737 | write(" then\n");
738 | indent(1);
739 | push_scope();
740 | process_node_list(data->body);
741 | pop_scope();
742 | indent(-1);
743 | if(data->next) process_node(data->next);
744 | else write("end\n");
745 | }
746 | }
747 | void process_elseif(AstNode* node){
748 | if(step==STEP_CHECK || step==STEP_OUTPUT){
749 | IfNode* data=(IfNode*)(node->data);
750 | write("elseif ");
751 | process_node(data->expr);
752 | write(" then\n");
753 | indent(1);
754 | push_scope();
755 | process_node_list(data->body);
756 | pop_scope();
757 | indent(-1);
758 | if(data->next) process_node(data->next);
759 | else write("end\n");
760 | }
761 | }
762 | void process_else(AstNode* node){
763 | if(step==STEP_CHECK || step==STEP_OUTPUT){
764 | write("else\n");
765 | indent(1);
766 | push_scope();
767 | process_node_list((List*)(node->data));
768 | pop_scope();
769 | indent(-1);
770 | write("end\n");
771 | }
772 | }
773 |
774 | /*
775 | Traverses through for loop nodes
776 | */
777 | void process_fornum(AstNode* node){
778 | if(step==STEP_CHECK || step==STEP_OUTPUT){
779 | FornumNode* data=(FornumNode*)(node->data);
780 | write("for %s=",data->name);
781 | process_node(data->num1);
782 | write(",");
783 | process_node(data->num2);
784 | if(data->num3){
785 | write(",");
786 | process_node(data->num3);
787 | }
788 | push_scope();
789 | write(" do\n");
790 | indent(1);
791 | process_node_list(data->body);
792 | indent(-1);
793 | write("end\n");
794 | pop_scope();
795 | }
796 | }
797 | void process_forin(AstNode* node){
798 | if(step==STEP_CHECK || step==STEP_OUTPUT){
799 | ForinNode* data=(ForinNode*)(node->data);
800 | write("for ");
801 | process_node(data->lhs);
802 | write(" in ");
803 | process_node(data->tuple);
804 | write(" do\n");
805 | indent(1);
806 | push_scope();
807 | process_node_list(data->body);
808 | indent(-1);
809 | write("end\n");
810 | pop_scope();
811 | }
812 | }
813 |
814 | /*
815 | Traverses through simple control statement nodes
816 | */
817 | void process_break(AstNode* node){
818 | if(step==STEP_OUTPUT){
819 | write("break\n");
820 | }
821 | }
822 | void process_label(AstNode* node){
823 | if(step==STEP_OUTPUT){
824 | write("::%s::\n",(char*)(node->data));
825 | }
826 | }
827 | void process_goto(AstNode* node){
828 | if(step==STEP_OUTPUT){
829 | write("goto %s\n",(char*)(node->data));
830 | }
831 | }
832 |
833 | /*
834 | Traverses through table and list nodes
835 | */
836 | void process_table(AstNode* node){
837 | if(step==STEP_CHECK || step==STEP_OUTPUT){
838 | TableNode* data=(TableNode*)(node->data);
839 | write("{");
840 | for(int a=0;akeys->n;a++){
841 | if(a) write(",");
842 | write("%s=",(char*)get_from_list(data->keys,a));
843 | process_node((AstNode*)get_from_list(data->vals,a));
844 | }
845 | write("}");
846 | }
847 | }
848 | void process_list_primitive_node(AstNode* node){
849 | if(step==STEP_CHECK || step==STEP_OUTPUT){
850 | AstNode* data=(AstNode*)(node->data);
851 | write("{");
852 | if(data) process_tuple(data);
853 | write("}");
854 | }
855 | }
856 |
857 | /*
858 | Traverses through primitive value nodes
859 | */
860 | void process_primitive(AstNode* node){
861 | if(step==STEP_OUTPUT){
862 | write("%s",((StringAstNode*)(node->data))->text);
863 | }
864 | }
865 | void process_tuple(AstNode* node){
866 | if(step==STEP_CHECK || step==STEP_OUTPUT){
867 | AstListNode* data=(AstListNode*)(node->data);
868 | List* ls=data->list;
869 | for(int a=0;an;a++){
870 | if(a) write(",");
871 | process_node((AstNode*)get_from_list(ls,a));
872 | }
873 | }
874 | }
875 |
876 | /*
877 | Traverses through expression nodes
878 | */
879 | void process_unary(AstNode* node){
880 | if(step==STEP_CHECK || step==STEP_OUTPUT){
881 | BinaryNode* data=(BinaryNode*)(node->data);
882 | if(strcmp(data->text,"trust")) write("%s ",data->text);
883 | process_node(data->l);
884 | }
885 | }
886 | void process_binary(AstNode* node){
887 | if(step==STEP_CHECK || step==STEP_OUTPUT){
888 | BinaryNode* data=(BinaryNode*)(node->data);
889 | process_node(data->l);
890 | if(strcmp(data->text,"as")){
891 | write(" %s ",data->text);
892 | process_node(data->r);
893 | }
894 | }
895 | }
896 | void process_paren(AstNode* node){
897 | if(step==STEP_CHECK || step==STEP_OUTPUT){
898 | write("(");
899 | process_node((AstNode*)(node->data));
900 | write(")");
901 | }
902 | }
903 |
--------------------------------------------------------------------------------
/src/types.c:
--------------------------------------------------------------------------------
1 | #include "./internal.h"
2 | #include
3 | #include
4 | #include
5 | static List* types_graph; // List of EqualTypesNodes
6 |
7 | /*
8 | Initialize the data structures used in this module
9 | */
10 | void init_types(){
11 | types_graph=new_default_list();
12 | }
13 |
14 | /*
15 | Deallocate registers and equivalence graphs
16 | */
17 | void dealloc_types(){
18 | // Quelling scoped type equivalences means there shouldn't be
19 | // any equivalences left by the time we get here
20 | assert(types_graph->n==0);
21 | dealloc_list(types_graph);
22 | }
23 |
24 | /*
25 | Deep copies a type to prevent deallocation errors
26 | */
27 | static AstNode* copy_type(AstNode* node){
28 | switch(node->type){
29 | case AST_TYPE_ANY: return new_node(AST_TYPE_ANY,-1,NULL);
30 | case AST_TYPE_VARARG: return new_node(AST_TYPE_VARARG,-1,NULL);
31 | case AST_TYPE_BASIC: return new_node(AST_TYPE_BASIC,-1,node->data);
32 | case AST_TYPE_TUPLE:{
33 | List* data=(List*)(node->data);
34 | List* ls=new_default_list();
35 | for(int a=0;an;a++){
36 | AstNode* copy=copy_type((AstNode*)get_from_list(data,a));
37 | add_to_list(ls,copy);
38 | }
39 | return new_node(AST_TYPE_TUPLE,-1,ls);
40 | }
41 | case AST_TYPE_FUNC:{
42 | AstListNode* data=(AstListNode*)(node->data);
43 | List* ls=new_default_list();
44 | for(int a=0;alist->n;a++){
45 | AstNode* e=copy_type((AstNode*)get_from_list(data->list,a));
46 | add_to_list(ls,e);
47 | }
48 | return new_node(AST_TYPE_FUNC,-1,new_ast_list_node(copy_type(data->node),ls));
49 | }
50 | }
51 | }
52 |
53 | /*
54 | Returns 1 if the AST_TYPE_* AstNode node is a AST_TYPE_BASIC node with value type
55 | */
56 | int is_primitive(AstNode* node,const char* type){
57 | return node->type==AST_TYPE_BASIC && !strcmp((char*)(node->data),type);
58 | }
59 |
60 | /*
61 | Returns the type of some entity's field name
62 | node is either a ClassNode or InterfaceNode, as specified by is_interface
63 | */
64 | static AstNode* get_type_of_field(char* name,void* data,int is_interface){
65 | AstNode* node=new_node(is_interface?AST_INTERFACE:AST_CLASS,-1,data);
66 | List* body=get_all_expected_fields(node);
67 | free(node);
68 | for(int a=0;an;a++){
69 | AstNode* e=(AstNode*)get_from_list(body,a);
70 | if(e->type==AST_FUNCTION){
71 | FunctionNode* func=(FunctionNode*)(e->data);
72 | if(func->name){
73 | char* funcname=(char*)(func->name->data);
74 | if(!strcmp(funcname,name)) return get_type(e);
75 | }
76 | }else{
77 | BinaryNode* def=(BinaryNode*)(e->data);
78 | if(!strcmp(def->text,name)) return def->l;
79 | }
80 | }
81 | return NULL;
82 | }
83 |
84 | // Functions for getting type nodes from various AstNodes
85 | static AstNode* get_ltuple_type(AstListNode* data){
86 | if(!data->node){
87 | List* ls=data->list;
88 | List* types=new_default_list();
89 | for(int a=0;an;a++){
90 | AstNode* e=(AstNode*)get_from_list(ls,a);
91 | add_to_list(types,copy_type(get_type(e)));
92 | }
93 | data->node=new_node(AST_TYPE_TUPLE,-1,types);
94 | }
95 | return data->node;
96 | }
97 | static AstNode* get_tuple_type(AstListNode* data){
98 | if(!data->node){
99 | List* ls=data->list;
100 | List* types=new_default_list();
101 | for(int a=0;an;a++){
102 | AstNode* e=(AstNode*)get_from_list(ls,a);
103 | add_to_list(types,copy_type(get_type(e)));
104 | }
105 | data->node=new_node(AST_TYPE_TUPLE,-1,types);
106 | }
107 | return data->node;
108 | }
109 | static AstNode* get_function_type(FunctionNode* data){
110 | if(!data->functype){
111 | List* ls=new_default_list();
112 | for(int a=0;aargs->n;a++){
113 | AstNode* e;
114 | StringAstNode* arg=(StringAstNode*)get_from_list(data->args,a);
115 | if(arg->node) e=copy_type(arg->node);
116 | else if(!strcmp(arg->text,"...")) e=new_node(AST_TYPE_VARARG,-1,NULL);
117 | else e=new_node(AST_TYPE_ANY,-1,NULL);
118 | add_to_list(ls,e);
119 | }
120 | data->functype=new_node(AST_TYPE_FUNC,-1,new_ast_list_node(copy_type(data->type),ls));
121 | }
122 | return data->functype;
123 | }
124 | static AstNode* get_super_type(){
125 | FunctionNode* method=get_method_scope();
126 | if(!method) return any_type_const();
127 | AstNode* node=new_node(AST_FUNCTION,-1,method);
128 | AstListNode* functype=(AstListNode*)(get_type(node)->data);
129 | free(node);
130 | return functype->node;
131 | }
132 | static AstNode* get_call_type(AstAstNode* data){
133 | AstNode* l=data->l;
134 | if(l->type==AST_ID){
135 | char* name=(char*)(l->data);
136 | FunctionNode* func=function_exists(name);
137 | if(func) return func->type;
138 | ClassNode* cnode=class_exists(name);
139 | if(cnode) return cnode->type;
140 | return any_type_const();
141 | }
142 | AstNode* type=get_type(l);
143 | if(type->type==AST_TYPE_ANY) return any_type_const();
144 | return ((AstListNode*)(type->data))->node;
145 | }
146 | static AstNode* get_id_type(AstNode* node){
147 | char* name=(char*)(node->data);
148 | StringAstNode* var=get_scoped_var(name);
149 | return (var && var->node)?(var->node):any_type_const();
150 | }
151 | static AstNode* get_field_type(StringAstNode* data){
152 | AstNode* ltype=get_type(data->node);
153 | if(ltype->type==AST_TYPE_BASIC){
154 | char* name=(char*)(ltype->data);
155 | InterfaceNode* inode=interface_exists(name);
156 | if(inode){
157 | AstNode* type=get_type_of_field(data->text,inode,1);
158 | if(type) return type;
159 | add_error(-1,"interface %s has no such field %s",inode->name,data->text);
160 | return any_type_const();
161 | }
162 | ClassNode* cnode=class_exists(name);
163 | if(cnode){
164 | AstNode* type=get_type_of_field(data->text,cnode,0);
165 | if(type) return type;
166 | add_error(-1,"class %s has no such field %s",cnode->name,data->text);
167 | return any_type_const();
168 | }
169 | }
170 | return any_type_const();
171 | }
172 | static AstNode* get_binary_type(BinaryNode* data){
173 | if(!strcmp(data->text,"as")){
174 | return data->r;
175 | }
176 | AstNode* tl=get_type(data->l);
177 | AstNode* tr=get_type(data->r);
178 | if(!strcmp(data->text,"..")){
179 | if(is_primitive(tl,PRIMITIVE_STRING) && is_primitive(tr,PRIMITIVE_STRING)) return tl;
180 | return any_type_const();
181 | }
182 | if(!strcmp(data->text,"/")){
183 | return float_type_const();
184 | }
185 | if(!strcmp(data->text,"+") || !strcmp(data->text,"-") || !strcmp(data->text,"*")){
186 | if(is_primitive(tl,PRIMITIVE_FLOAT)) return tl;
187 | if(is_primitive(tr,PRIMITIVE_FLOAT)) return tr;
188 | return int_type_const();
189 | }
190 | return bool_type_const();
191 | }
192 |
193 | /*
194 | Finds an AST_TYPE_* AstNode for the input AstNode
195 | Never free the result of this function, it will be deallocated elsewhere
196 | */
197 | AstNode* get_type(AstNode* node){
198 | int type=node->type;
199 | switch(node->type){
200 | case AST_FUNCTION: return get_function_type((FunctionNode*)(node->data));
201 | case AST_FIELD: return get_field_type((StringAstNode*)(node->data));
202 | case AST_LTUPLE: return get_ltuple_type((AstListNode*)(node->data));
203 | case AST_BINARY: return get_binary_type((BinaryNode*)(node->data));
204 | case AST_TUPLE: return get_tuple_type((AstListNode*)(node->data));
205 | case AST_PRIMITIVE: return ((StringAstNode*)(node->data))->node;
206 | case AST_CALL: return get_call_type((AstAstNode*)(node->data));
207 | case AST_PAREN: return get_type((AstNode*)(node->data));
208 | case AST_DEFINE: return ((BinaryNode*)(node->data))->l;
209 | case AST_UNARY: return ((BinaryNode*)(node->data))->r;
210 | case AST_REQUIRE: return any_type_const();
211 | case AST_SUPER: return get_super_type();
212 | case AST_SUB: return any_type_const();
213 | case AST_ID: return get_id_type(node);
214 | default: return any_type_const();
215 | }
216 | }
217 |
218 | /*
219 | Returns 1 if the FunctionNode has a variadic parameter
220 | args is a list of AST_TYPE_* nodes
221 | */
222 | int is_variadic_function(List* args){
223 | if(!args->n) return 0;
224 | AstNode* arg=(AstNode*)get_from_list(args,args->n-1);
225 | return arg->type==AST_TYPE_VARARG;
226 | }
227 |
228 | /*
229 | Returns 1 if the type r can be placed into a variable of type l
230 | */
231 | static int typed_match_no_equivalence(AstNode* l,AstNode* r){
232 | if(l->type==AST_TYPE_ANY) return 1;
233 | if(!r) return 0;
234 | if(is_primitive(r,PRIMITIVE_NIL)) return 1;
235 | if(is_primitive(l,PRIMITIVE_FLOAT) && is_primitive(r,PRIMITIVE_INT)) return 1;
236 | if(l->type==AST_TYPE_BASIC && r->type==AST_TYPE_BASIC){
237 | return !strcmp((char*)(l->data),(char*)(r->data));
238 | }
239 | if(l->type==AST_TYPE_TUPLE && r->type==AST_TYPE_TUPLE){
240 | List* lls=(List*)(l->data);
241 | List* rls=(List*)(r->data);
242 | if(lls->n!=rls->n) return 0;
243 | for(int a=0;an;a++){
244 | AstNode* nl=(AstNode*)get_from_list(lls,a);
245 | AstNode* nr=(AstNode*)get_from_list(rls,a);
246 | int match=typed_match(nl,nr);
247 | if(!match) return 0;
248 | }
249 | return 1;
250 | }
251 | if(l->type==AST_TYPE_FUNC && r->type==AST_TYPE_FUNC){
252 | AstListNode* ldata=(AstListNode*)(l->data);
253 | AstListNode* rdata=(AstListNode*)(r->data);
254 | if(!typed_match(ldata->node,rdata->node)) return 0;
255 | int max=ldata->list->n;
256 | if(is_variadic_function(ldata->list)){
257 | if(rdata->list->nlist->n-1) return 0;
258 | max=ldata->list->n-1;
259 | }else{
260 | if(rdata->list->n!=ldata->list->n) return 0;
261 | }
262 | for(int a=0;alist,a),(AstNode*)get_from_list(rdata->list,a))) return 0;
264 | }
265 | return 1;
266 | }
267 | return 0;
268 | }
269 |
270 | /*
271 | Returns 1 if the types r and l are an exact match
272 | Or returns 1 if the type r can be placed into a variable of type l
273 | */
274 | int typed_match(AstNode* l,AstNode* r){
275 | if(!l) return 1;
276 | if(r && l->type==AST_TYPE_BASIC && types_equivalent((char*)(l->data),r)) return 1;
277 | return typed_match_no_equivalence(l,r);
278 | }
279 |
280 | /*
281 | Boils a typedef type down into its lowest-level typedef
282 | Returns the input type if it is already at its lowest typedef link
283 | */
284 | char* base_type(char* name){
285 | while(1){
286 | for(int a=0;an;a++){
287 | EqualTypesNode* node=(EqualTypesNode*)get_from_list(types_graph,a);
288 | if(node->relation==RL_EQUALS && node->type->type==AST_TYPE_BASIC && !strcmp(node->name,name)){
289 | name=(char*)(node->type->data);
290 | continue;
291 | }
292 | }
293 | break;
294 | }
295 | return name;
296 | }
297 |
298 | /*
299 | Goes recursively through a compound type (tuple or function) or singular type
300 | Returns 1 if every type referenced in the compound type exists
301 | */
302 | int compound_type_exists(AstNode* node){
303 | if(!node) return 1;
304 | switch(node->type){
305 | case AST_TYPE_ANY: return 1;
306 | case AST_TYPE_VARARG: return 1;
307 | case AST_TYPE_BASIC:{
308 | char* t=(char*)(node->data);
309 | if(!type_exists(t)) return 0;
310 | return 1;
311 | }
312 | case AST_TYPE_TUPLE:{
313 | List* ls=(List*)(node->data);
314 | for(int a=0;an;a++){
315 | if(!compound_type_exists((AstNode*)get_from_list(ls,a))) return 0;
316 | }
317 | return 1;
318 | }
319 | case AST_TYPE_FUNC:{
320 | AstListNode* data=(AstListNode*)(node->data);
321 | if(!compound_type_exists(data->node)) return 0;
322 | for(int a=0;alist->n;a++){
323 | if(!compound_type_exists((AstNode*)get_from_list(data->list,a))) return 0;
324 | }
325 | return 1;
326 | }
327 | }
328 | assert(0); // You should never get here
329 | }
330 |
331 | /*
332 | Checks for a path from name to type in the equivalent types graph
333 | Returns 1 if such a path exists
334 | */
335 | static int path_exists(char* name,AstNode* type){
336 | List* ls=get_equivalent_types(name);
337 | int a=0;
338 | while(an){
339 | AstNode* node=get_from_list(ls,a);
340 | if(typed_match_no_equivalence(node,type)){
341 | dealloc_list(ls);
342 | return 1;
343 | }
344 | if(node->type==AST_TYPE_BASIC){
345 | List* ls1=get_equivalent_types((char*)(node->data));
346 | for(int b=0;bn;b++) add_to_list(ls,get_from_list(ls1,b));
347 | dealloc_list(ls1);
348 | }
349 | a++;
350 | }
351 | dealloc_list(ls);
352 | return 0;
353 | }
354 |
355 | /*
356 | Creates a type equivalence for entity types (classes and interfaces)
357 | Just a wrapper around add_type_equivalence
358 | */
359 | int add_child_type(char* child,char* parent,int relation){
360 | AstNode* r=new_node(AST_TYPE_BASIC,-1,child);
361 | return add_type_equivalence(parent,r,relation);
362 | }
363 |
364 | /*
365 | Registers a type relationship as a path in the equivalent types graph
366 | name points to type in the graph
367 | Returns 0 if this will create a cycle
368 | */
369 | int add_type_equivalence(char* name,AstNode* type,int relation){
370 | if(type->type==AST_TYPE_BASIC){
371 | AstNode* r=new_node(AST_TYPE_BASIC,-1,name);
372 | char* l=(char*)(type->data);
373 | int cycle=path_exists(l,r);
374 | free(r);
375 | if(cycle) return 0;
376 | }
377 | assert(get_num_scopes()>0); // Ensure that there is a scope
378 | add_to_list(types_graph,new_equal_types_node(name,type,relation,get_num_scopes()));
379 | return 1;
380 | }
381 |
382 | /*
383 | Returns a List of AST_TYPE_* AstNodes
384 | List is full of types that are equivalent to name with 1 degree of separation
385 | */
386 | List* get_equivalent_types(char* name){
387 | List* ls=new_default_list();
388 | for(int a=0;an;a++){
389 | EqualTypesNode* node=(EqualTypesNode*)get_from_list(types_graph,a);
390 | if(!strcmp(node->name,name)) add_to_list(ls,node->type);
391 | }
392 | return ls;
393 | }
394 |
395 | /*
396 | Returns 1 if two types are equivalent (or if type is a subtype of name)
397 | */
398 | int types_equivalent(char* name,AstNode* type){
399 | if(type->type==AST_TYPE_BASIC && !strcmp(name,(char*)(type->data))) return 1;
400 | return path_exists(name,type);
401 | }
402 |
403 | /*
404 | Cleans expired edges from the types equivalency graph
405 | Expired means we have exited the scope that an equivalence was defined in
406 | */
407 | void quell_expired_scope_equivalences(int scope){
408 | int a=0;
409 | while(an){
410 | EqualTypesNode* node=(EqualTypesNode*)get_from_list(types_graph,a);
411 | assert(node->scope<=scope);
412 | if(node->scope==scope){
413 | remove_from_list(types_graph,a);
414 | }else{
415 | a++;
416 | }
417 | }
418 | }
419 |
420 | /*
421 | Internal recursive function that helps with type stringification
422 | */
423 | static void stringify_type_internal(List* ls,AstNode* node){
424 | if(!node || node->type==AST_TYPE_ANY){
425 | add_to_list(ls,"var");
426 | }else if(node->type==AST_TYPE_VARARG){
427 | add_to_list(ls,"...");
428 | }else if(node->type==AST_TYPE_BASIC){
429 | add_to_list(ls,node->data);
430 | }else if(node->type==AST_TYPE_TUPLE){
431 | List* tls=(List*)(node->data);
432 | add_to_list(ls,"(");
433 | for(int a=0;an;a++){
434 | if(a) add_to_list(ls,",");
435 | stringify_type_internal(ls,(AstNode*)get_from_list(tls,a));
436 | }
437 | add_to_list(ls,")");
438 | }else if(node->type==AST_TYPE_FUNC){
439 | AstListNode* data=(AstListNode*)(node->data);
440 | if(ls->n==0 || strcmp((char*)get_from_list(ls,ls->n-1),"*")){
441 | add_to_list(ls,"*");
442 | }
443 | stringify_type_internal(ls,data->node);
444 | add_to_list(ls,"(");
445 | for(int a=0;alist->n;a++){
446 | if(a) add_to_list(ls,",");
447 | stringify_type_internal(ls,(AstNode*)get_from_list(data->list,a));
448 | }
449 | add_to_list(ls,")");
450 | }
451 | }
452 |
453 | /*
454 | Converts a AST_TYPE_* AstNode into a string representation
455 | Very helpful for error formatting and debugging
456 | */
457 | char* stringify_type(AstNode* node){
458 | int len=1;
459 | List* ls=new_default_list();
460 | stringify_type_internal(ls,node);
461 | for(int a=0;an;a++) len+=strlen((char*)get_from_list(ls,a));
462 | char* type=(char*)malloc(sizeof(char)+len);
463 | type[0]=0;
464 | for(int a=0;an;a++) strcat(type,(char*)get_from_list(ls,a));
465 | dealloc_list(ls);
466 | return type;
467 | }
468 |
469 | /*
470 | Print out types equivalence graph
471 | */
472 | void print_types_graph(){
473 | for(int a=0;an;a++){
474 | EqualTypesNode* e=(EqualTypesNode*)get_from_list(types_graph,a);
475 | char* type=stringify_type(e->type);
476 | printf("%i: %s -> %s\n",e->relation,e->name,type);
477 | free(type);
478 | }
479 | }
480 |
--------------------------------------------------------------------------------
/testing/outputs/basic.txt:
--------------------------------------------------------------------------------
1 | Goodbye
2 | Adios
3 | Hello
4 | Yellow
5 | Yo whaddup
6 | Yo whaddup
7 | tee hee tummy tums1234
8 |
--------------------------------------------------------------------------------
/testing/outputs/chaining.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lugocorp/moonshot/f9f24d12797bd6153d6e1858149821663f51b239/testing/outputs/chaining.txt
--------------------------------------------------------------------------------
/testing/outputs/class.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lugocorp/moonshot/f9f24d12797bd6153d6e1858149821663f51b239/testing/outputs/class.txt
--------------------------------------------------------------------------------
/testing/outputs/classes.txt:
--------------------------------------------------------------------------------
1 | 1
2 |
--------------------------------------------------------------------------------
/testing/outputs/comments.txt:
--------------------------------------------------------------------------------
1 | Hello
2 |
--------------------------------------------------------------------------------
/testing/outputs/functions.txt:
--------------------------------------------------------------------------------
1 | Hello there!
2 | 6
3 | yellow
4 | red
5 |
--------------------------------------------------------------------------------
/testing/outputs/ifchains.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lugocorp/moonshot/f9f24d12797bd6153d6e1858149821663f51b239/testing/outputs/ifchains.txt
--------------------------------------------------------------------------------
/testing/outputs/operators.txt:
--------------------------------------------------------------------------------
1 | 4
2 | 10
3 | 13
4 | 13
5 | 91.0
6 | 91.0
7 | 83.0
8 | 83.0
9 | 1253.0
10 | 1253.0
11 | -2
12 | -10
13 | 7
14 | -7
15 | -71.0
16 | 71.0
17 | 77.0
18 | -77.0
19 | 1247.0
20 | -1247.0
21 | 2
22 | -10
23 | -7
24 | -7
25 | 10.012345679012
26 | 71.0
27 | -77.0
28 | 3.3125
29 | -1247.0
30 | -1247.0
31 | -7
32 | 7
33 | 71.0
34 | -71.0
35 | 3.3125
36 | -77.0
37 | -1247.0
38 | 3.0032
39 | 71.0
40 | 10.012345679012
41 | -77.0
42 | 77.0
43 | 3.0032
44 | 1247.0
45 |
--------------------------------------------------------------------------------
/testing/outputs/reference.txt:
--------------------------------------------------------------------------------
1 | Reference here
2 |
--------------------------------------------------------------------------------
/testing/outputs/require.txt:
--------------------------------------------------------------------------------
1 | Reference here
2 | Hello!
3 |
--------------------------------------------------------------------------------
/testing/outputs/syntax.txt:
--------------------------------------------------------------------------------
1 | 7
2 | 1
3 | 2
4 | 3
5 | Got to hello
6 | Got to hello
7 | Goodbye lol
8 |
--------------------------------------------------------------------------------
/testing/outputs/trust.txt:
--------------------------------------------------------------------------------
1 | Hello, world!
2 |
--------------------------------------------------------------------------------
/testing/outputs/variadic.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lugocorp/moonshot/f9f24d12797bd6153d6e1858149821663f51b239/testing/outputs/variadic.txt
--------------------------------------------------------------------------------
/testing/queries/basic.lua:
--------------------------------------------------------------------------------
1 | function sup()
2 | return red==0
3 | end
4 | red=0
5 |
6 | function hello()
7 | msg="Hello there"
8 | while sup() do
9 | msg="Ello gov'nor"
10 | end
11 | if not red then
12 | red=1
13 | end
14 | print("msg")
15 | end
16 |
17 | do
18 | print("Goodbye")
19 | print("Ad".."i".."os")
20 | end
21 |
22 | function yellow() print("Yellow") end
23 | function hello() print("Hello") end
24 |
25 | repeat
26 | hello()
27 | red=127.11
28 | until 1==1
29 |
30 | while 1 do
31 | red=false
32 | yo=yellow()
33 | break
34 | end
35 |
36 | for a=0,1 do
37 | print("Yo whaddup")
38 | end
39 |
40 | t={a=1,b=2,c=3}
41 | for k,_ in ipairs(t) do
42 | print(k)
43 | end
44 |
45 | do
46 | print("tee hee tummy tums".."1234")
47 | end
48 |
--------------------------------------------------------------------------------
/testing/queries/chaining.moon:
--------------------------------------------------------------------------------
1 |
2 | class OlderTest where
3 | constructor()
4 | print("Old days")
5 | end
6 |
7 | int number()
8 | return 0
9 | end
10 | end
11 |
12 | class OldTest extends OlderTest where
13 | constructor(int x)
14 | super()
15 | print("Happy days")
16 | end
17 |
18 | var hello()
19 | a=1
20 | end
21 | end
22 |
23 | class Test extends OldTest where
24 | constructor()
25 | super(1)
26 | end
27 |
28 | string hello()
29 | super()
30 | return "hello"
31 | end
32 |
33 | int number()
34 | return super()
35 | end
36 | end
37 |
38 | class YoOld where
39 | int a
40 |
41 | constructor(int a)
42 | this.a=a
43 | end
44 | end
45 |
46 | class YoChild extends YoOld where
47 | constructor()
48 | super(123)
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/testing/queries/class.moon:
--------------------------------------------------------------------------------
1 |
2 | class Testing where
3 | int a=0
4 |
5 | constructor(int a)
6 | this.a=a
7 | a=a
8 | end
9 |
10 | int get_a2()
11 | return this.a+a
12 | end
13 |
14 | var other()
15 | a=1
16 | get_a2()
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/testing/queries/classes.moon:
--------------------------------------------------------------------------------
1 |
2 | interface Methods where
3 | string hello()
4 | var whatsup()
5 | (int,int) coords(int a)
6 | end
7 |
8 | class Math implements Methods where
9 | int name=1
10 | string hello()
11 | return "Hi there"
12 | end
13 | var whatsup() end
14 | (int,int) coords(int a)
15 | return a,a+1
16 | end
17 | end
18 |
19 | Math m=Math()
20 | int a=m.name
21 |
22 | class Log where
23 | constructor(int a)
24 | print(a)
25 | end
26 | end
27 |
28 | Log l=Log(1)
29 |
30 | class Math1 extends Math where
31 |
32 | end
33 |
34 | class TestThis where
35 | int a=1
36 |
37 | var increment()
38 | this.a=this.a+1
39 | return this.a
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/testing/queries/comments.moon:
--------------------------------------------------------------------------------
1 | --local lib=require "library"
2 | --[[require "hello"]]
3 |
4 | --[[""]]
5 |
6 | -- Hello function!
7 | function hello()
8 | print("Hello")
9 | end
10 |
11 | --[[here's our function call]] hello()
12 |
--------------------------------------------------------------------------------
/testing/queries/functions.moon:
--------------------------------------------------------------------------------
1 | function hello(msg)
2 | print(msg)
3 | end
4 | hello("Hello there!")
5 |
6 | int number(int d)
7 | return d+5
8 | end
9 | print(number(1))
10 |
11 | (string,string) colors()
12 | return "yellow","red"
13 | end
14 | yellow,red=colors()
15 |
16 | print(yellow)
17 | print(red)
18 |
--------------------------------------------------------------------------------
/testing/queries/ifchains.moon:
--------------------------------------------------------------------------------
1 |
2 | if true then
3 |
4 | elseif yo then
5 |
6 | elseif true then
7 |
8 | else
9 |
10 | end
11 |
12 | if true then
13 |
14 | elseif yo then
15 |
16 | else
17 |
18 | end
19 |
20 |
21 | if true then
22 |
23 | elseif false then
24 |
25 | end
26 |
27 | if true then
28 |
29 | else
30 |
31 | end
32 |
33 | if hi then
34 |
35 | end
36 |
--------------------------------------------------------------------------------
/testing/queries/operators.lua:
--------------------------------------------------------------------------------
1 |
2 | print( 3+1 )
3 | print( 2*5 )
4 | print( 3+2*5 )
5 | print( 2*5+3 )
6 | print( 3^4+2*5 )
7 | print( 2*5+3^4 )
8 | print( 3+2^4*5 )
9 | print( 2^4*5+3 )
10 | print( 3+2*5^4 )
11 | print( 2*5^4+3 )
12 |
13 |
14 | print( -3+1 )
15 | print( -2*5 )
16 | print( -3+2*5 )
17 | print( -2*5+3 )
18 | print( -3^4+2*5 )
19 | print( -2*5+3^4 )
20 | print( -3+2^4*5 )
21 | print( -2^4*5+3 )
22 | print( -3+2*5^4 )
23 | print( -2*5^4+3 )
24 |
25 | print( 3+-1 )
26 | print( 2*-5 )
27 | print( 3+-2*5 )
28 | print( 2*-5+3 )
29 | print( 3^-4+2*5 )
30 | print( 2*-5+3^4 )
31 | print( 3+-2^4*5 )
32 | print( 2^-4*5+3 )
33 | print( 3+-2*5^4 )
34 | print( 2*-5^4+3 )
35 |
36 | print( 3+2*-5 )
37 | print( 2*5+-3 )
38 | print( 3^4+-2*5 )
39 | print( 2*5+-3^4 )
40 | print( 3+2^-4*5 )
41 | print( 2^4*-5+3 )
42 | print( 3+2*-5^4 )
43 | print( 2*5^-4+3 )
44 |
45 | print( 3^4+2*-5 )
46 | print( 2*5+3^-4 )
47 | print( 3+2^4*-5 )
48 | print( 2^4*5+-3 )
49 | print( 3+2*5^-4 )
50 | print( 2*5^4+-3 )
51 |
--------------------------------------------------------------------------------
/testing/queries/reference.moon:
--------------------------------------------------------------------------------
1 |
2 | typedef Message string
3 |
4 | class Messenger where
5 | var sendMessage(Message m)
6 |
7 | end
8 | end
9 |
10 | class Hello where
11 | Goodbye gb
12 | end
13 |
14 | class Goodbye where
15 | Hello h
16 | end
17 |
18 | print("Reference here")
19 |
--------------------------------------------------------------------------------
/testing/queries/require.moon:
--------------------------------------------------------------------------------
1 | require "testing/queries/reference.moon"
2 | Messenger msngr
3 | print("Hello!")
4 |
--------------------------------------------------------------------------------
/testing/queries/syntax.moon:
--------------------------------------------------------------------------------
1 |
2 |
3 | string greeting="Greetings!"
4 |
5 | interface Test where
6 |
7 | end
8 | class Object implements Test where
9 | (int,int) greet(int a)
10 | print(a)
11 | return a,a
12 | end
13 | end
14 |
15 | typedef Thing Object
16 | Thing obj=Object()
17 |
18 | repeat
19 | a,b=obj.greet(-3+(5*2))
20 | until true
21 |
22 | local tab={msg="hello"}
23 | do
24 | if true then
25 | tab["msg"]="goodbye"
26 | end
27 | end
28 |
29 | for a=1,3 do
30 | print(a)
31 | end
32 | for k,v in ipairs(tab) do
33 | print(k)
34 | end
35 |
36 | while false do
37 | break
38 | end
39 |
40 | a=true
41 | ::hello::
42 | print("Got to hello")
43 | if a then
44 | a=false
45 | goto hello
46 | end
47 | print("Goodbye lol")
48 |
--------------------------------------------------------------------------------
/testing/queries/trust.moon:
--------------------------------------------------------------------------------
1 | local msg="Hello, world!"
2 | string msg1=trust msg
3 | print(msg1)
4 |
--------------------------------------------------------------------------------
/testing/queries/variadic.moon:
--------------------------------------------------------------------------------
1 |
2 | (string,string) hello(string a,...)
3 | string b=trust arg[1]
4 | if b==nil then
5 | b="b"
6 | end
7 | return a.." x "..b,a
8 | end
9 |
10 | hello("1","yo","extra","ignore me lol")
11 | hello("hi")
12 |
13 | function test()
14 |
15 | end
16 |
17 | test()
18 |
19 | function goodbye(...)
20 |
21 | end
22 |
23 | goodbye(1,2,3)
24 | goodbye()
25 |
--------------------------------------------------------------------------------
/testing/run:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | make moonshot
3 | [ "$?" == 1 ] && exit 1
4 | moontests=( $(ls testing/queries | grep -e "\.moon$") )
5 | luatests=( $(ls testing/queries | grep -e "\.lua$") )
6 | tmp="bin/vanilla.txt"
7 | tmp2="bin/moon.txt"
8 | src="bin/src.lua"
9 | successes=0
10 | failures=0
11 | echo ""
12 |
13 | # Run Moon tests
14 | for test in "${moontests[@]}"; do
15 | output="testing/outputs/${test/.moon/.txt}"
16 | ./moonshot --print "testing/queries/$test" > $src
17 | if [ "$?" == 0 ]; then
18 | cat "$src" | lua5.3 > "$tmp2" 2>&1
19 | else
20 | cat "$src" > "$tmp2"
21 | fi
22 | diff "$tmp2" "$output" > /dev/null 2>&1
23 | if [ $? == 0 ]; then
24 | successes="$(expr $successes + 1)"
25 | else
26 | failures="$(expr $failures + 1)"
27 | echo -e "\033[4m$failures) $test\033[0m"
28 | echo -e "\033[1mExpected:\033[0m"
29 | cat "$output"
30 | echo ""
31 | echo -e "\033[1mActual:\033[0m"
32 | cat "$tmp2"
33 | echo ""
34 | fi
35 | done
36 |
37 | # Run Lua tests
38 | for test in "${luatests[@]}"; do
39 | output="testing/outputs/${test/.lua/.txt}"
40 | ./moonshot --print "testing/queries/$test" > $src
41 | if [ "$?" == 0 ]; then
42 | cat "$src" | lua5.3 > "$tmp2" 2>&1
43 | else
44 | cat "$src" > "$tmp2"
45 | fi
46 | diff "$tmp2" "$output" > /dev/null 2>&1
47 | if [ $? == 0 ]; then
48 | cat "testing/queries/$test" | lua5.3 > "$tmp" 2>&1
49 | diff "$tmp" "$tmp2" > /dev/null 2>&1
50 | if [ $? == 0 ]; then
51 | successes="$(expr $successes + 1)"
52 | else
53 | failures="$(expr $failures + 1)"
54 | echo -e "\033[4m$failures) $test\033[0m"
55 | echo -e "\033[1mExpected:\033[0m"
56 | cat "$tmp"
57 | echo ""
58 | echo -e "\033[1mActual:\033[0m"
59 | cat "$tmp2"
60 | echo ""
61 | fi
62 | else
63 | failures="$(expr $failures + 1)"
64 | echo -e "\033[4m$failures) $test\033[0m"
65 | echo -e "\033[1mExpected:\033[0m"
66 | cat "$output"
67 | echo ""
68 | echo -e "\033[1mActual:\033[0m"
69 | cat "$tmp2"
70 | echo ""
71 | fi
72 | done
73 |
74 | # Print results
75 | echo -e "\033[4mResults\033[0m"
76 | echo -e "$(expr $successes + $failures) \033[1mtotal\033[0m"
77 | echo -e "$successes \033[1m\033[32msuccesses\033[0m"
78 | if [ "$failures" -gt "0" ]; then
79 | echo -e "$failures \033[1m\033[31mfailures\033[0m"
80 | fi
81 |
--------------------------------------------------------------------------------
/tools/cli.c:
--------------------------------------------------------------------------------
1 | #include "../src/moonshot.h"
2 | #include
3 | #include
4 |
5 | // Output
6 | static void error(){
7 | printf("\033[31;1merror:\033[0m ");
8 | }
9 | static void indent(int i,const char* msg){
10 | for(int a=0;a");
18 | indent(2,"Set output file\n");
19 | indent(1,"--version");
20 | indent(2,"Print Moonshot version\n");
21 | indent(1,"--print");
22 | indent(3,"Write Lua code to stdout\n");
23 | indent(1,"--help");
24 | indent(3," Print usage options\n");
25 | }
26 |
27 | // Argument parsing
28 | static int check_args(FILE** output,char** source,int argc,char** argv,int a){
29 | if(!strcmp(argv[a],"--version")){
30 | printf("Moonshot v%s\n",VERSION);
31 | return 2;
32 | }
33 | if(!strcmp(argv[a],"--help")){
34 | help();
35 | return 2;
36 | }
37 | if(!strcmp(argv[a],"--print")){
38 | if(*output){
39 | error();
40 | printf("output is already defined\n");
41 | return 1;
42 | }
43 | *output=stdout;
44 | }else if(!strcmp(argv[a],"-o")){
45 | if(a==argc-1){
46 | help();
47 | return 1;
48 | }
49 | if(*output){
50 | error();
51 | printf("output is already defined\n");
52 | return 1;
53 | }
54 | *output=fopen(argv[a+1],"w");
55 | }else{
56 | if(a1) printf("Moonshot compiler returned %i errors\n",n);
110 | for(int a=0;a