From 606daa625bdb49c110cadd28d4a18b82995dadf3 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Mon, 18 Jan 2021 23:11:53 +0100 Subject: [PATCH] Refactor, improve, and repair --- Makefile.generic-package | 8 + packages/compiler/LICENCE | 1 + packages/compiler/Makefile | 1 + packages/compiler/gpl-3.0.txt | 674 ++++++++++++++++++ packages/compiler/package-lock.json | 5 + packages/compiler/package.json | 20 + packages/compiler/rollup.config.js | 51 ++ packages/compiler/src/compiler/codegen.ts | 231 ++++++ .../src/compiler/grammar.ts | 47 +- .../{core => compiler}/src/compiler/index.ts | 0 packages/compiler/src/compiler/internals.ts | 7 + packages/compiler/src/index.ts | 20 + .../src/syntax/codewriter.ts | 4 +- .../{core => compiler}/src/syntax/index.ts | 0 .../{core => compiler}/src/syntax/list.ts | 0 .../{core => compiler}/src/syntax/matcher.ts | 39 +- packages/compiler/src/syntax/position.ts | 41 ++ .../{core => compiler}/src/syntax/reader.ts | 24 +- .../{core => compiler}/src/syntax/scanner.ts | 18 +- .../{core => compiler}/src/syntax/template.ts | 20 +- .../{core => compiler}/src/syntax/tokens.ts | 37 +- packages/{core => compiler}/src/syntax/vlq.ts | 0 packages/compiler/tsconfig.json | 17 + packages/core/Makefile | 9 +- packages/core/README.md | 2 +- packages/core/bin/syndicatec.js | 79 -- packages/core/examples/box-and-client.js | 6 +- packages/core/package.json | 10 +- packages/core/src/bin/syndicate-compiler.ts | 1 - packages/core/src/compiler/codegen.ts | 218 ------ packages/core/src/compiler/internals.ts | 1 - packages/core/src/index.ts | 3 - packages/core/src/runtime/api.ts | 2 + packages/core/src/runtime/ground.ts | 31 +- packages/core/src/syntax/position.ts | 32 - packages/syndicatec/LICENCE | 1 + packages/syndicatec/Makefile | 1 + packages/syndicatec/bin/syndicatec.js | 2 + .../syndicatec/examples/javascript/.gitignore | 1 + .../examples/javascript/index.syndicate.js | 42 ++ .../examples/javascript/package.json | 19 + packages/syndicatec/gpl-3.0.txt | 674 ++++++++++++++++++ packages/syndicatec/package.json | 27 + packages/syndicatec/src/cli.ts | 95 +++ packages/syndicatec/src/index.ts | 1 + packages/syndicatec/tsconfig.json | 17 + 46 files changed, 2094 insertions(+), 445 deletions(-) create mode 100644 Makefile.generic-package create mode 120000 packages/compiler/LICENCE create mode 120000 packages/compiler/Makefile create mode 100644 packages/compiler/gpl-3.0.txt create mode 100644 packages/compiler/package-lock.json create mode 100644 packages/compiler/package.json create mode 100644 packages/compiler/rollup.config.js create mode 100644 packages/compiler/src/compiler/codegen.ts rename packages/{core => compiler}/src/compiler/grammar.ts (92%) rename packages/{core => compiler}/src/compiler/index.ts (100%) create mode 100644 packages/compiler/src/compiler/internals.ts create mode 100644 packages/compiler/src/index.ts rename packages/{core => compiler}/src/syntax/codewriter.ts (98%) rename packages/{core => compiler}/src/syntax/index.ts (100%) rename packages/{core => compiler}/src/syntax/list.ts (100%) rename packages/{core => compiler}/src/syntax/matcher.ts (87%) create mode 100644 packages/compiler/src/syntax/position.ts rename packages/{core => compiler}/src/syntax/reader.ts (82%) rename packages/{core => compiler}/src/syntax/scanner.ts (93%) rename packages/{core => compiler}/src/syntax/template.ts (74%) rename packages/{core => compiler}/src/syntax/tokens.ts (69%) rename packages/{core => compiler}/src/syntax/vlq.ts (100%) create mode 100644 packages/compiler/tsconfig.json mode change 100644 => 120000 packages/core/Makefile delete mode 100755 packages/core/bin/syndicatec.js delete mode 100644 packages/core/src/bin/syndicate-compiler.ts delete mode 100644 packages/core/src/compiler/codegen.ts delete mode 100644 packages/core/src/compiler/internals.ts delete mode 100644 packages/core/src/syntax/position.ts create mode 120000 packages/syndicatec/LICENCE create mode 120000 packages/syndicatec/Makefile create mode 100755 packages/syndicatec/bin/syndicatec.js create mode 100644 packages/syndicatec/examples/javascript/.gitignore create mode 100755 packages/syndicatec/examples/javascript/index.syndicate.js create mode 100644 packages/syndicatec/examples/javascript/package.json create mode 100644 packages/syndicatec/gpl-3.0.txt create mode 100644 packages/syndicatec/package.json create mode 100644 packages/syndicatec/src/cli.ts create mode 100644 packages/syndicatec/src/index.ts create mode 100644 packages/syndicatec/tsconfig.json diff --git a/Makefile.generic-package b/Makefile.generic-package new file mode 100644 index 0000000..ab0b079 --- /dev/null +++ b/Makefile.generic-package @@ -0,0 +1,8 @@ +all: + npm run prepare + +clean: + rm -rf lib dist .nyc_output coverage tsconfig.tsbuildinfo + +veryclean: clean + rm -rf node_modules package-lock.json diff --git a/packages/compiler/LICENCE b/packages/compiler/LICENCE new file mode 120000 index 0000000..725d276 --- /dev/null +++ b/packages/compiler/LICENCE @@ -0,0 +1 @@ +gpl-3.0.txt \ No newline at end of file diff --git a/packages/compiler/Makefile b/packages/compiler/Makefile new file mode 120000 index 0000000..0e892c3 --- /dev/null +++ b/packages/compiler/Makefile @@ -0,0 +1 @@ +../../Makefile.generic-package \ No newline at end of file diff --git a/packages/compiler/gpl-3.0.txt b/packages/compiler/gpl-3.0.txt new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/packages/compiler/gpl-3.0.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/packages/compiler/package-lock.json b/packages/compiler/package-lock.json new file mode 100644 index 0000000..e670c56 --- /dev/null +++ b/packages/compiler/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@syndicate-lang/compiler", + "version": "0.0.1", + "lockfileVersion": 1 +} diff --git a/packages/compiler/package.json b/packages/compiler/package.json new file mode 100644 index 0000000..712b5f1 --- /dev/null +++ b/packages/compiler/package.json @@ -0,0 +1,20 @@ +{ + "name": "@syndicate-lang/compiler", + "version": "0.0.1", + "description": "Syndicate/JS compiler library", + "homepage": "https://github.com/syndicate-lang/syndicate-js/tree/master/packages/compiler", + "license": "GPL-3.0+", + "publishConfig": { + "access": "public" + }, + "repository": "github:syndicate-lang/syndicate-js", + "scripts": { + "prepare": "npm run compile && npm run rollup", + "compile": "../../node_modules/.bin/tsc", + "rollup": "../../node_modules/.bin/rollup -c" + }, + "main": "dist/syndicate-compiler.js", + "module": "lib/index.js", + "types": "lib/index.d.ts", + "author": "Tony Garnock-Jones " +} diff --git a/packages/compiler/rollup.config.js b/packages/compiler/rollup.config.js new file mode 100644 index 0000000..56a0519 --- /dev/null +++ b/packages/compiler/rollup.config.js @@ -0,0 +1,51 @@ +import resolve from '@rollup/plugin-node-resolve'; +import { terser } from 'rollup-plugin-terser'; + +function distfile(insertion) { + const f = `syndicate-compiler${insertion}.js`; + return `dist/${f}`; +} + +function umd(insertion, extra) { + return { + file: distfile(insertion), + format: 'umd', + name: 'SyndicateCompiler', + ... (extra || {}) + }; +} + +function es6(insertion, extra) { + return { + file: distfile('.es6' + insertion), + format: 'es', + ... (extra || {}) + }; +} + +export default [ + { + input: 'lib/index.js', + plugins: [ + resolve({ + preferBuiltins: false, + }), + ], + output: [ + umd(''), + umd('.min', { plugins: [terser()] }), + ], + }, { + input: 'lib/index.js', + plugins: [ + resolve({ + // moduleDirectories: ['stubs', 'node_modules'], + preferBuiltins: false, + }), + ], + output: [ + es6(''), + es6('.min', { plugins: [terser()] }), + ], + } +]; diff --git a/packages/compiler/src/compiler/codegen.ts b/packages/compiler/src/compiler/codegen.ts new file mode 100644 index 0000000..37120bd --- /dev/null +++ b/packages/compiler/src/compiler/codegen.ts @@ -0,0 +1,231 @@ +import { + isToken, isTokenType, replace, commaJoin, startPos, fixPos, + + Items, Pattern, Templates, Substitution, TokenType, + SourceMap, StringScanner, LaxReader, CodeWriter, TemplateFunction, +} from '../syntax/index.js'; +import { + FacetAction, Statement, + + compilePattern, + patternText, + + spawn, + fieldDeclarationStatement, + assertionEndpointStatement, + dataflowStatement, + eventHandlerEndpointStatement, + duringStatement, + typeDefinitionStatement, + messageSendStatement, + reactStatement, + bootStatement, + stopStatement, +} from './grammar.js'; +import { + BootProc, +} from './internals.js'; + +export function stripShebang(items: Items): Items { + if ((items.length > 0) && + isToken(items[0]) && + items[0].text.startsWith('#!')) { + while (items.length > 0 && !isTokenType(items[0], TokenType.NEWLINE)) items.shift(); + } + return items; +} + +export type ModuleType ='es6' | 'require' | 'global'; + +export interface CompileOptions { + source: string, + name?: string, + runtime?: string, + module?: ModuleType, + global?: string, +} + +export interface CompilerOutput { + text: string, + map: SourceMap, +} + +function receiverFor(s: FacetAction): Substitution { + return (s.implicitFacet) ? 'thisFacet.' : '.'; +} + +export function expand(tree: Items, moduleType: ModuleType): Items { + const macro = new Templates(); + + function terminalWrap(t: TemplateFunction, isTerminal: boolean, body: Statement): Statement { + if (isTerminal) { + return t`thisFacet._stop(function (thisFacet) {${body}})` + } else { + return body; + } + } + + function x(p: Pattern, f: (v: T, t: TemplateFunction) => Items) { + tree = replace(tree, p, (v, start) => f(v, macro.template(fixPos(start)))); + } + + function xf(p: Pattern, f: (v: T, t: TemplateFunction) => Items) { + x(p, (v, t) => t`${receiverFor(v)}${f(v, t)}`); + } + + const walk = (tree: Items): Items => expand(tree, moduleType); + const maybeWalk = (tree?: Items) : Items | undefined => (tree === void 0) ? tree : walk(tree); + + xf(duringStatement, (s, t) => { + // TODO: spawn during + const sa = compilePattern(s.pattern); + return t`withSelfDo(function (thisFacet) { + const _Facets = new __SYNDICATE__.Dictionary(); + on asserted ${patternText(s.pattern)} => react { + _Facets.set([${commaJoin(sa.captureIds.map(t=>[t]))}], thisFacet); + dataflow void 0; // TODO: horrible hack to keep the facet alive if no other endpoints + ${s.body} + } + on retracted ${patternText(s.pattern)} => { + const _Key = [${commaJoin(sa.captureIds.map(t=>[t]))}]; + _Facets.get(_Key)._stop(); + _Facets.delete(_Key); + } + });`; + }); + + xf(spawn, (s, t) => { + let proc = t`function (thisFacet) {${walk(s.bootProcBody)}}`; + if (s.isDataspace) proc = t`__SYNDICATE__.inNestedDataspace(${proc})`; + let assertions = (s.initialAssertions.length > 0) + ? t`, new __SYNDICATE__.Set([${commaJoin(s.initialAssertions.map(walk))}])` + : ``; + return t`_spawn(${maybeWalk(s.name) ?? 'null'}, ${proc}${assertions});`; + }); + + xf(fieldDeclarationStatement, (s, t) => { + const prop = ('name' in s.property) + ? [ { start: s.property.name.start, + end: s.property.name.end, + type: TokenType.STRING, + text: JSON.stringify(s.property.name.text) } ] + : walk(s.property.expr); + return t`declareField(${walk(s.target)}, ${prop}, ${maybeWalk(s.init) ?? 'void 0'});`; + }); + + xf(assertionEndpointStatement, (s, t) => { + if (s.test == void 0) { + return t`addEndpoint(thisFacet => ({ assertion: ${walk(s.template)}, analysis: null }));`; + } else { + return t`addEndpoint(thisFacet => (${walk(s.test)}) + ? ({ assertion: ${walk(s.template)}, analysis: null }) + : ({ assertion: void 0, analysis: null }), ${''+s.isDynamic});`; + } + }); + + xf(dataflowStatement, (s, t) => t`addDataflow(function (thisFacet) {${walk(s.body)}});`); + + xf(eventHandlerEndpointStatement, (s, t) => { + switch (s.triggerType) { + case 'dataflow': + return t`withSelfDo(function (thisFacet) { dataflow { if (${walk(s.predicate)}) { ${terminalWrap(t, s.terminal, walk(s.body))} } } });`; + + case 'start': + case 'stop': { + const m = s.triggerType === 'start' ? 'addStartScript' : 'addStopScript'; + return t`${m}(function (thisFacet) {${walk(s.body)}});`; + } + + case 'asserted': + case 'retracted': + case 'message': { + const sa = compilePattern(s.pattern); + const expectedEvt = ({ + 'asserted': 'ADDED', + 'retracted': 'REMOVED', + 'message': 'MESSAGE', + })[s.triggerType]; + return t`addEndpoint(thisFacet => ({ + assertion: __SYNDICATE__.Observe(${walk(sa.assertion)}), + analysis: { + skeleton: ${walk(sa.skeleton)}, + constPaths: ${JSON.stringify(sa.constPaths)}, + constVals: [${commaJoin(sa.constVals.map(walk))}], + capturePaths: ${JSON.stringify(sa.capturePaths)}, + callback: thisFacet.wrap((thisFacet, __Evt, [${commaJoin(sa.captureIds.map(i=>[i]))}]) => { + if (__Evt === __SYNDICATE__.Skeleton.EventType.${expectedEvt}) { + thisFacet.scheduleScript(() => {${terminalWrap(t, s.terminal, walk(s.body))}}); + } + }) + } + }), ${'' + s.isDynamic});`; + } + } + }); + + x(typeDefinitionStatement, (s, t) => { + const l = JSON.stringify(s.label.text); + const fs = JSON.stringify(s.fields.map(f => f.text)); + return t`const ${[s.label]} = __SYNDICATE__.Record.makeConstructor(${maybeWalk(s.wireName) ?? l}, ${fs});`; + }); + + xf(messageSendStatement, (s, t) => t`_send(${walk(s.expr)});`); + + xf(reactStatement, (s, t) => t`addChildFacet(function (thisFacet) {${walk(s.body)}});`); + + x(bootStatement, (s, t) => { + switch (moduleType) { + case 'es6': + return t`export function ${BootProc}(thisFacet) {${walk(s)}}`; + case 'global': + return t`module.exports.${BootProc} = function (thisFacet) {${walk(s)}};`; + case 'require': + return t`function ${BootProc}(thisFacet) {${walk(s)}}`; + } + }); + + xf(stopStatement, (s, t) => t`_stop(function (thisFacet) {${walk(s.body)}});`) + + return tree; +} + +export function compile(options: CompileOptions): CompilerOutput { + const inputFilename = options.name ?? '/dev/stdin'; + const source = options.source; + const moduleType = options.module ?? 'es6'; + + const start = startPos(inputFilename); + + const scanner = new StringScanner(start, source); + const reader = new LaxReader(scanner); + let tree = stripShebang(reader.readToEnd()); + let macro = new Templates(); + + const end = tree.length > 0 ? tree[tree.length - 1].end : start; + + { + const runtime = options.runtime ?? '@syndicate-lang/core'; + const t = macro.template(fixPos(start)); + switch (moduleType) { + case 'es6': + tree = t`import * as __SYNDICATE__ from ${JSON.stringify(runtime)};\n${tree}`; + break; + case 'require': + tree = t`const __SYNDICATE__ = require(${JSON.stringify(runtime)});\n${tree}`; + break; + case 'global': + tree = t`const __SYNDICATE__ = ${runtime};\n${tree}`; + break; + } + } + + tree = macro.template(fixPos(end))`${tree}\nif ((typeof require === 'undefined' ? {main: void 0} : require).main === module) __SYNDICATE__.bootModule(${BootProc});`; + + const cw = new CodeWriter(inputFilename); + cw.emit(expand(tree, moduleType)); + + return { + text: cw.text, + map: cw.map, + }; +} diff --git a/packages/core/src/compiler/grammar.ts b/packages/compiler/src/compiler/grammar.ts similarity index 92% rename from packages/core/src/compiler/grammar.ts rename to packages/compiler/src/compiler/grammar.ts index 7873441..486cb8b 100644 --- a/packages/core/src/compiler/grammar.ts +++ b/packages/compiler/src/compiler/grammar.ts @@ -6,21 +6,18 @@ import { scope, bind, seq, alt, upTo, atom, atomString, group, exec, repeat, option, withoutSpace, map, mapm, rest, discard, - value, succeed, fail, separatedBy, anything, + value, succeed, fail, separatedBy, anything, not, } from '../syntax/index.js'; import * as Matcher from '../syntax/matcher.js'; -import { Path, Skeleton } from '../runtime/api.js'; +import { Path, Skeleton } from './internals.js'; export type Expr = Items; export type Statement = Items; export type Identifier = Token; -export const block = (acc?: Items) => - (acc === void 0) - ? group('{', discard) - : group('{', map(rest, items => acc.push(... items))); +export const block = (acc: Items) => group('{', map(rest, items => acc.push(... items))); -export const statementBoundary = alt(atom(';'), Matcher.newline, Matcher.end); +export const statementBoundary = alt(atom(';'), Matcher.newline); export const exprBoundary = alt(atom(';'), atom(','), group('{', discard), Matcher.end); export const identifier: Pattern = atom(); @@ -29,8 +26,8 @@ export function expr(... extraStops: Pattern[]): Pattern { return withoutSpace(upTo(alt(exprBoundary, ... extraStops))); } -export function statement(acc: Items): Pattern { - return alt(group('{', map(rest, items => acc.push(... items))), +export function statement(acc: Items): Pattern { + return alt(block(acc), withoutSpace(seq(map(upTo(statementBoundary), items => acc.push(... items)), map(statementBoundary, i => i ? acc.push(i) : void 0)))); } @@ -83,7 +80,7 @@ export const spawn: Pattern & { headerExpr: Pattern } = o.parentIds.push(l.id); o.parentInits.push(l.init); }))), - statement(o.bootProcBody)); + block(o.bootProcBody)); }), { headerExpr: expr(atom(':asserting'), atom(':let')), }); @@ -127,15 +124,15 @@ export interface StatementFacetAction extends FacetAction { body: Statement; } -export function statementFacetAction(kw: Pattern): Pattern { +export function blockFacetAction(kw: Pattern): Pattern { return facetAction(o => { o.body = []; - return seq(kw, statement(o.body)); + return seq(kw, block(o.body)); }); } // Principal: Facet -export const dataflowStatement = statementFacetAction(atom('dataflow')); +export const dataflowStatement = blockFacetAction(atom('dataflow')); export interface GenericEventEndpointStatement extends StatementFacetAction { terminal: boolean; @@ -159,6 +156,12 @@ export interface AssertionEventEndpointStatement extends GenericEventEndpointSta export type EventHandlerEndpointStatement = DataflowEndpointStatement | PseudoEventEndpointStatement | AssertionEventEndpointStatement; +export function mandatoryIfNotTerminal(o: GenericEventEndpointStatement, p: Pattern): Pattern { + return i => { + return (o.terminal) ? option(p)(i) : p(i); + }; +} + // Principal: Facet export const eventHandlerEndpointStatement: Pattern = facetAction(o => { @@ -170,7 +173,7 @@ export const eventHandlerEndpointStatement: Pattern(seq(map(group('(', bind(o as DataflowEndpointStatement, 'predicate', expr())), _ => o.triggerType = 'dataflow'), - option(statement(o.body))), + mandatoryIfNotTerminal(o, statement(o.body))), mapm(seq(bind(o, 'triggerType', alt(atomString('start'), atomString('stop'))), option(statement(o.body))), @@ -182,8 +185,7 @@ export const eventHandlerEndpointStatement: Pattern o.isDynamic = false)), bind(o as AssertionEventEndpointStatement, 'pattern', valuePattern(atom('=>'))), - alt(seq(atom('=>'), statement(o.body)), - statementBoundary)))); + mandatoryIfNotTerminal(o, seq(atom('=>'), statement(o.body)))))); }); export interface TypeDefinitionStatement { @@ -210,6 +212,8 @@ export interface MessageSendStatement extends FacetAction { // Principal: Facet export const messageSendStatement: Pattern = facetAction(o => seq(atom('send'), + atom('message'), + not(statementBoundary), bind(o, 'expr', withoutSpace(upTo(statementBoundary))), statementBoundary)); @@ -224,22 +228,21 @@ export const duringStatement: Pattern = o.body = []; return seq(atom('during'), bind(o, 'pattern', valuePattern(atom('=>'))), - alt(seq(atom('=>'), statement(o.body)), - statementBoundary)); + seq(atom('=>'), statement(o.body))); }); // Principal: Facet -export const reactStatement = statementFacetAction(atom('react')); +export const reactStatement = blockFacetAction(atom('react')); // Principal: none export const bootStatement: Pattern = value(o => { o.value = []; - return seq(atom('boot'), statement(o.value)); + return seq(atom('boot'), block(o.value)); }); // Principal: Facet -export const stopStatement = statementFacetAction(atom('stop')); +export const stopStatement = blockFacetAction(atom('stop')); //--------------------------------------------------------------------------- // Syntax of patterns over Value, used in endpoints @@ -282,7 +285,7 @@ const pDiscard: Pattern = mapm(identifier, i => i.text === '_' ? succeed(v function hasCapturesOrDiscards(e: Expr): boolean { return foldItems(e, t => match(alt(pCaptureId, pDiscard), [t], null) !== null, - (_s, _e, b, _k) => b, + (_g, b, _k) => b, bs => bs.some(b => b)); } diff --git a/packages/core/src/compiler/index.ts b/packages/compiler/src/compiler/index.ts similarity index 100% rename from packages/core/src/compiler/index.ts rename to packages/compiler/src/compiler/index.ts diff --git a/packages/compiler/src/compiler/internals.ts b/packages/compiler/src/compiler/internals.ts new file mode 100644 index 0000000..e5c0fc8 --- /dev/null +++ b/packages/compiler/src/compiler/internals.ts @@ -0,0 +1,7 @@ +export const BootProc = '__SYNDICATE__bootProc'; + +// Keep these definitions in sync with api.ts from the core package +// +export type NonEmptySkeleton = { shape: Shape, members: Skeleton[] }; +export type Skeleton = null | NonEmptySkeleton; +export type Path = Array; diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts new file mode 100644 index 0000000..ac1519c --- /dev/null +++ b/packages/compiler/src/index.ts @@ -0,0 +1,20 @@ +//--------------------------------------------------------------------------- +// @syndicate-lang/compiler, an implementation of Syndicate dataspaces for JS. +// Copyright (C) 2016-2021 Tony Garnock-Jones +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +//--------------------------------------------------------------------------- + +export * as Syntax from './syntax/index.js'; +export * from './compiler/index.js'; diff --git a/packages/core/src/syntax/codewriter.ts b/packages/compiler/src/syntax/codewriter.ts similarity index 98% rename from packages/core/src/syntax/codewriter.ts rename to packages/compiler/src/syntax/codewriter.ts index ad45fa9..9fd6a2f 100644 --- a/packages/core/src/syntax/codewriter.ts +++ b/packages/compiler/src/syntax/codewriter.ts @@ -162,9 +162,9 @@ export class CodeWriter { if (Array.isArray(i)) { i.forEach(j => this.emit(j)); } else if (isGroup(i)) { - this.emit(i.start); + this.emit(i.open); this.emit(i.items); - if (i.end) this.emit(i.end); + if (i.close) this.emit(i.close); } else if (i === null) { // Do nothing. } else { diff --git a/packages/core/src/syntax/index.ts b/packages/compiler/src/syntax/index.ts similarity index 100% rename from packages/core/src/syntax/index.ts rename to packages/compiler/src/syntax/index.ts diff --git a/packages/core/src/syntax/list.ts b/packages/compiler/src/syntax/list.ts similarity index 100% rename from packages/core/src/syntax/list.ts rename to packages/compiler/src/syntax/list.ts diff --git a/packages/core/src/syntax/matcher.ts b/packages/compiler/src/syntax/matcher.ts similarity index 87% rename from packages/core/src/syntax/matcher.ts rename to packages/compiler/src/syntax/matcher.ts index d2ff1f7..1b7d531 100644 --- a/packages/core/src/syntax/matcher.ts +++ b/packages/compiler/src/syntax/matcher.ts @@ -1,5 +1,8 @@ -import { Token, TokenType, Items, Item, isGroup, isToken, isSpace, isTokenType } from './tokens.js'; -import { Pos } from './position.js'; +import { + Token, TokenType, Items, Item, + isGroup, isToken, isSpace, isTokenType, +} from './tokens.js'; +import { Pos, startPos } from './position.js'; import { List, ArrayList, atEnd, notAtEnd } from './list.js'; //--------------------------------------------------------------------------- @@ -23,10 +26,7 @@ export function succeed(t: T): Pattern { return i => [t, i]; } export const discard: Pattern = _i => [void 0, noItems]; export const rest: Pattern = i => [i.toArray(), noItems]; export const end: Pattern = i => atEnd(skipSpace(i)) ? [void 0, noItems] : null; -export const pos: Pattern = i => - notAtEnd(i) - ? [isGroup(i.item) ? i.item.start.start : i.item.start, i] - : null; +export const pos: Pattern = i => notAtEnd(i) ? [i.item.start, i] : null; export const newline: Pattern = i => { while (notAtEnd(i) && isTokenType(i.item, TokenType.SPACE)) i = i.next; @@ -51,7 +51,12 @@ export function withoutSpace(p: Pattern): Pattern { return i => p(skipSpace(i)); } -export function seq(... patterns: Pattern[]): Pattern { +export function not(p: Pattern, v?: undefined): Pattern; +export function not(p: Pattern, v: T): Pattern { + return i => p(i) === null ? [v, i] : null; +} + +export function seq(... patterns: Pattern[]): Pattern { return i => { for (const p of patterns) { const r = p(i); @@ -139,7 +144,7 @@ export function group(opener: string, items: Pattern, options: GroupOption if (options.skipSpace ?? true) i = skipSpace(i); if (!notAtEnd(i)) return null; if (!isGroup(i.item)) return null; - if (i.item.start.text !== opener) return null; + if (i.item.open.text !== opener) return null; const r = items(new ArrayList(i.item.items)); if (r === null) return null; if (!atEnd(r[1])) return null; @@ -244,28 +249,32 @@ export function option(p: Pattern): Pattern { //--------------------------------------------------------------------------- // Search-and-replace over Item -export function replace(items: Items, - p: Pattern, - f: (t: T) => Items): Items +export function replace( + items: Items, + p: Pattern, + f: (t: T, start: Pos, end: Pos) => Items, + end: Pos = items.length > 0 ? items[items.length - 1].end : startPos(null)) : Items { - const walkItems = (items: Items): Items => { + const walkItems = (items: Items, end: Pos): Items => { let i: List = new ArrayList(items); const acc: Items = []; while (notAtEnd(i = collectSpace(i, acc))) { const r = p(i); if (r !== null) { - acc.push(... f(r[0])); + acc.push(... f(r[0], + notAtEnd(i) ? i.item.start : end, + notAtEnd(r[1]) ? r[1].item.start : end)); i = r[1]; } else if (isToken(i.item)) { acc.push(i.item); i = i.next; } else { - acc.push({ ... i.item, items: walkItems(i.item.items) }); + acc.push({ ... i.item, items: walkItems(i.item.items, i.item.end) }); i = i.next; } } return acc; }; - return walkItems(items); + return walkItems(items, end); } diff --git a/packages/compiler/src/syntax/position.ts b/packages/compiler/src/syntax/position.ts new file mode 100644 index 0000000..8706ab7 --- /dev/null +++ b/packages/compiler/src/syntax/position.ts @@ -0,0 +1,41 @@ +export interface Pos { + line: number; + column: number; + pos: number; + name: string | null; + fixed?: boolean; +} + +export function startPos(name: string | null): Pos { + return { line: 1, column: 0, pos: 0, name }; +} + +export function fixPos(p: Pos): Pos { + return { ... p, fixed: true }; +} + +export function advancePos(p: Pos, ch: string): boolean { + if (p.fixed ?? false) { + return ch === '\n'; + } else { + let advancedLine = false; + p.pos++; + switch (ch) { + case '\t': + p.column = (p.column + 8) & ~7; + break; + case '\n': + p.column = 0; + p.line++; + advancedLine = true; + break; + case '\r': + p.column = 0; + break; + default: + p.column++; + break; + } + return advancedLine; + } +} diff --git a/packages/core/src/syntax/reader.ts b/packages/compiler/src/syntax/reader.ts similarity index 82% rename from packages/core/src/syntax/reader.ts rename to packages/compiler/src/syntax/reader.ts index d828847..ed18b94 100644 --- a/packages/core/src/syntax/reader.ts +++ b/packages/compiler/src/syntax/reader.ts @@ -1,4 +1,4 @@ -import { TokenType, Token, Group, Item, Items } from './tokens.js'; +import { TokenType, Token, Group, GroupInProgress, Item, Items, finishGroup } from './tokens.js'; import { Pos, startPos } from './position.js'; import { Scanner, StringScanner } from './scanner.js'; @@ -13,7 +13,7 @@ function matchingParen(c: string): string | null { export class LaxReader implements IterableIterator { readonly scanner: Scanner; - readonly stack: Array = []; + readonly stack: Array = []; constructor(scanner: Scanner) { this.scanner = scanner; @@ -23,23 +23,23 @@ export class LaxReader implements IterableIterator { return this; } - stackTop(): Group | null { + stackTop(): GroupInProgress | null { return this.stack[this.stack.length - 1] ?? null; } popUntilMatch(t: Token): Group | 'continue' | 'eof' { const m = matchingParen(t.text); - if (m !== null && !this.stack.some(g => g.start.text === m)) { + if (m !== null && !this.stack.some(g => g.open.text === m)) { if (this.stack.length > 0) { this.stackTop()!.items.push(t); return 'continue'; } } else { while (this.stack.length > 0) { - const inner = this.stack.pop()!; - if (inner.start.text === m) { - inner.end = t; + const inner = finishGroup(this.stack.pop()!, t.end); + if (inner.open.text === m) { + inner.close = t; } if (this.stack.length === 0) { @@ -47,7 +47,7 @@ export class LaxReader implements IterableIterator { } else { const outer = this.stackTop()!; outer.items.push(inner); - if (inner.start.text === m) { + if (inner.open.text === m) { return 'continue'; } } @@ -79,14 +79,14 @@ export class LaxReader implements IterableIterator { return t; } if (t.text === ';') { - while ('(['.indexOf(g.start.text) >= 0) { + while ('(['.indexOf(g.open.text) >= 0) { this.stack.pop(); const outer = this.stackTop(); if (outer === null) { // do not drop the semicolon here - return g; + return finishGroup(g, t.start); } - outer.items.push(g); + outer.items.push(finishGroup(g, t.start)); g = outer; } } @@ -96,7 +96,7 @@ export class LaxReader implements IterableIterator { case TokenType.OPEN: this.drop(); - this.stack.push({ start: t, end: null, items: [] }); + this.stack.push(this.scanner.makeGroupInProgress(t)); break; case TokenType.CLOSE: { diff --git a/packages/core/src/syntax/scanner.ts b/packages/compiler/src/syntax/scanner.ts similarity index 93% rename from packages/core/src/syntax/scanner.ts rename to packages/compiler/src/syntax/scanner.ts index a778a0e..30477af 100644 --- a/packages/core/src/syntax/scanner.ts +++ b/packages/compiler/src/syntax/scanner.ts @@ -1,4 +1,4 @@ -import { TokenType, Token } from './tokens.js'; +import { TokenType, Token, Item, GroupInProgress } from './tokens.js'; import { Pos, advancePos } from './position.js'; export abstract class Scanner implements IterableIterator { @@ -16,6 +16,7 @@ export abstract class Scanner implements IterableIterator { } abstract _peekChar(): string | null; + abstract _dropChar(): void; peekChar(): string | null { if (this.charBuffer !== null) return this.charBuffer; @@ -26,6 +27,7 @@ export abstract class Scanner implements IterableIterator { dropChar() { if (this.charBuffer === null) this.peekChar(); if (this.charBuffer !== null) { + this._dropChar(); advancePos(this.pos, this.charBuffer); this.charBuffer = null; } @@ -41,6 +43,10 @@ export abstract class Scanner implements IterableIterator { return { type, start, end: this.mark(), text }; } + makeGroupInProgress(open: Token, items: Array = []): GroupInProgress { + return { start: open.start, open, close: null, items }; + } + mark(): Pos { return { ... this.pos }; } @@ -203,15 +209,19 @@ export abstract class Scanner implements IterableIterator { export class StringScanner extends Scanner { readonly input: string; - readonly startPos: number; + index: number; constructor(pos: Pos, input: string) { super(pos); this.input = input; - this.startPos = this.pos.pos; + this.index = 0; } _peekChar(): string | null { - return this.input[this.pos.pos - this.startPos] ?? null; + return this.input[this.index] ?? null; + } + + _dropChar(): void { + this.index++; } } diff --git a/packages/core/src/syntax/template.ts b/packages/compiler/src/syntax/template.ts similarity index 74% rename from packages/core/src/syntax/template.ts rename to packages/compiler/src/syntax/template.ts index 14be93b..bd406bf 100644 --- a/packages/core/src/syntax/template.ts +++ b/packages/compiler/src/syntax/template.ts @@ -13,10 +13,18 @@ function toItems(s: Substitution, pos: Pos): Items { return typeof s === 'string' ? laxRead(s, { start: pos }) : s; } +export type TemplateFunction = (consts: TemplateStringsArray, ... vars: Substitution[]) => Items; + export class Templates { readonly sources: { [name: string]: string } = {}; + readonly defaultPos: Pos; + recordSources = false; - template(start0: Pos | string = startPos(null)): (consts: TemplateStringsArray, ... vars: Substitution[]) => Items { + constructor(defaultPos: Pos = startPos(null)) { + this.defaultPos = defaultPos; + } + + template(start0: Pos | string = this.defaultPos): TemplateFunction { const start = (typeof start0 === 'string') ? startPos(start0) : start0; return (consts, ... vars) => { const sourcePieces = [consts[0]]; @@ -25,11 +33,13 @@ export class Templates { sourcePieces.push(consts[i]); } const source = sourcePieces.join(''); - if (start.name !== null) { - if (start.name in this.sources && this.sources[start.name] !== source) { - throw new Error(`Duplicate template name: ${start.name}`); + if (this.recordSources) { + if (start.name !== null) { + if (start.name in this.sources && this.sources[start.name] !== source) { + throw new Error(`Duplicate template name: ${start.name}`); + } + this.sources[start.name] = source; } - this.sources[start.name] = source; } let i = 0; return M.replace(laxRead(source, { start, extraDelimiters: '$' }), diff --git a/packages/core/src/syntax/tokens.ts b/packages/compiler/src/syntax/tokens.ts similarity index 69% rename from packages/core/src/syntax/tokens.ts rename to packages/compiler/src/syntax/tokens.ts index 988e522..28e73c8 100644 --- a/packages/core/src/syntax/tokens.ts +++ b/packages/compiler/src/syntax/tokens.ts @@ -1,4 +1,4 @@ -import { Pos, startPos } from './position.js'; +import { Pos } from './position.js'; export enum TokenType { SPACE, @@ -9,34 +9,33 @@ export enum TokenType { CLOSE, } -export interface Token { - type: TokenType; +export interface TokenBase { start: Pos; end: Pos; +} + +export interface Token extends TokenBase { + type: TokenType; text: string; } -export interface Group { - start: Token; - end: Token | null; +export interface Group extends TokenBase { + open: Token; + close: Token | null; items: Items; } export type Item = Token | Group; export type Items = Array; -export function makeToken(text: string, name?: string | null, type: TokenType = TokenType.ATOM): Token { - const p = startPos(name ?? null); - return { - start: p, - end: p, - type, - text - }; +export type GroupInProgress = Omit; + +export function finishGroup(g: GroupInProgress, end: Pos): Group { + return { ... g, end }; } -export function makeGroup(start: Token, items: Array, end?: Token) { - return { start, end: end ?? null, items }; +export function makeGroup(open: Token, items: Array, close: Token): Group { + return { start: open.start, open, end: close.end, close, items }; } export function isSpace(i: Item): i is Token { @@ -62,12 +61,12 @@ export type ItemTextOptions = { export function foldItems(i: Items, fToken: (t: Token) => T, - fGroup: (start: Token, end: Token | null, t: T, k: (t: Token) => T) => T, + fGroup: (g: Group, t: T, k: (t: Token) => T) => T, fItems: (ts: T[]) => T): T { const walk = (i: Item): T => { if (isGroup(i)) { - return fGroup(i.start, i.end, fItems(i.items.map(walk)), walk); + return fGroup(i, fItems(i.items.map(walk)), walk); } else { return fToken(i); } @@ -93,6 +92,6 @@ export function itemText(items: Items, options: ItemTextOptions = {}): string { return i.text; } }, - (start, end, inner, k) => k(start) + inner + (end ? k(end) : options.missing ?? ''), + (g, inner, k) => k(g.open) + inner + (g.close ? k(g.close) : options.missing ?? ''), strs => strs.join('')); } diff --git a/packages/core/src/syntax/vlq.ts b/packages/compiler/src/syntax/vlq.ts similarity index 100% rename from packages/core/src/syntax/vlq.ts rename to packages/compiler/src/syntax/vlq.ts diff --git a/packages/compiler/tsconfig.json b/packages/compiler/tsconfig.json new file mode 100644 index 0000000..983aa20 --- /dev/null +++ b/packages/compiler/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["ES2017", "DOM"], + "declaration": true, + "baseUrl": "./src", + "rootDir": "./src", + "outDir": "./lib", + "declarationDir": "./lib", + "esModuleInterop": true, + "moduleResolution": "node", + "module": "es6", + "sourceMap": true, + "strict": true + }, + "include": ["src/**/*"] +} diff --git a/packages/core/Makefile b/packages/core/Makefile deleted file mode 100644 index ab0b079..0000000 --- a/packages/core/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -all: - npm run prepare - -clean: - rm -rf lib dist .nyc_output coverage tsconfig.tsbuildinfo - -veryclean: clean - rm -rf node_modules package-lock.json diff --git a/packages/core/Makefile b/packages/core/Makefile new file mode 120000 index 0000000..0e892c3 --- /dev/null +++ b/packages/core/Makefile @@ -0,0 +1 @@ +../../Makefile.generic-package \ No newline at end of file diff --git a/packages/core/README.md b/packages/core/README.md index b06d521..a2db160 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -6,7 +6,7 @@ An implementation of the *Dataspace* model that underpins the ## Licence @syndicate-lang/core, an implementation of Syndicate dataspaces for JS. -Copyright (C) 2016-2018 Tony Garnock-Jones +Copyright (C) 2016-2021 Tony Garnock-Jones This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/packages/core/bin/syndicatec.js b/packages/core/bin/syndicatec.js deleted file mode 100755 index afd1cb2..0000000 --- a/packages/core/bin/syndicatec.js +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env node - -const yargs = require('yargs/yargs'); -const { hideBin } = require('yargs/helpers'); -const argv = - yargs(hideBin(process.argv)) - .completion() - .command('$0 [input]', 'Compile a single file', (yargs) => { - yargs - .positional('input', { - type: 'string', - description: 'Input filename', - }) - .option('output', { - alias: 'o', - type: 'string', - description: 'Output filename (stdout if omitted)', - default: null, - }) - .option('map', { - type: 'boolean', - description: 'Generate source maps', - default: true, - }) - .option('map-extension', { - type: 'string', - description: 'Extension (e.g. ".map") to add to source map files; if omitted, source maps are generated inline', - default: null, - }) - .option('runtime', { - type: 'string', - description: 'Path to require or import to get the Syndicate runtime', - default: '@syndicate/core', - }) - .option('module', { - type: 'string', - description: 'es6 | require | global', - }) - }) - .argv; - -const fs = require('fs'); -const { compile } = require('../dist/syndicate.js').Compiler; - -// console.log(argv); - -const inputFilename = 'input' in argv ? argv.input : '/dev/stdin'; -const source = fs.readFileSync(inputFilename, 'utf-8'); - -const { text, map } = compile({ - source, - name: inputFilename, - runtime: argv.runtime, - module: argv.module, -}); -map.sourcesContent = [source]; - -function mapDataURL() { - const mapData = Buffer.from(JSON.stringify(map)).toString('base64') - return `data:application/json;base64,${mapData}`; -} - -if (argv.output !== null) { - if (!argv.map) { - fs.writeFileSync(argv.output, text); - } else if (argv.mapExtension) { - const mapFilename = argv.output + argv.mapExtension; - fs.writeFileSync(argv.output, text + `\n//# sourceMappingURL=${mapFilename}`); - fs.writeFileSync(mapFilename, JSON.stringify(map)); - } else { - fs.writeFileSync(argv.output, text + `\n//# sourceMappingURL=${mapDataURL()}`); - } -} else { - if (!argv.map) { - console.log(text); - } else { - console.log(text + `\n//# sourceMappingURL=${mapDataURL()}`); - } -} diff --git a/packages/core/examples/box-and-client.js b/packages/core/examples/box-and-client.js index 8e700ba..0d288e5 100755 --- a/packages/core/examples/box-and-client.js +++ b/packages/core/examples/box-and-client.js @@ -17,7 +17,7 @@ // along with this program. If not, see . //--------------------------------------------------------------------------- -const { Dataspace, Skeleton, Ground, Record, Discard, Capture, Observe } = require('../dist/syndicate.js'); +const { bootModule, Dataspace, Skeleton, Ground, Record, Discard, Capture, Observe } = require('../dist/syndicate.js'); const __ = Discard._instance; const _$ = Capture(__); @@ -87,6 +87,4 @@ function boot(thisFacet) { console.timeEnd('box-and-client-' + N.toString())); } -module.exports.boot = boot; - -new Ground(boot).start(); +bootModule(boot); diff --git a/packages/core/package.json b/packages/core/package.json index ac09c6b..214300c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@syndicate-lang/core", "version": "0.4.1", - "description": "Imperative Syndicate in the browser", + "description": "Syndicate/JS for browser and node.js", "homepage": "https://github.com/syndicate-lang/syndicate-js/tree/master/packages/core", "license": "GPL-3.0+", "publishConfig": { @@ -10,7 +10,7 @@ "repository": "github:syndicate-lang/syndicate-js", "scripts": { "prepare": "npm run compile && npm run rollup", - "compile": "../../node_modules/.bin/tsc --incremental", + "compile": "../../node_modules/.bin/tsc", "rollup": "../../node_modules/.bin/rollup -c", "test": "../../node_modules/.bin/jest", "cover": "../../node_modules/.bin/nyc --reporter=html ../../node_modules/.bin/jest" @@ -20,10 +20,6 @@ "types": "lib/index.d.ts", "author": "Tony Garnock-Jones ", "dependencies": { - "preserves": "0.4.0", - "yargs": "^16.2.0" - }, - "bin": { - "syndicatec": "./bin/syndicatec.js" + "preserves": "0.4.0" } } diff --git a/packages/core/src/bin/syndicate-compiler.ts b/packages/core/src/bin/syndicate-compiler.ts deleted file mode 100644 index ec10f3e..0000000 --- a/packages/core/src/bin/syndicate-compiler.ts +++ /dev/null @@ -1 +0,0 @@ -console.log('hi'); diff --git a/packages/core/src/compiler/codegen.ts b/packages/core/src/compiler/codegen.ts deleted file mode 100644 index 4586453..0000000 --- a/packages/core/src/compiler/codegen.ts +++ /dev/null @@ -1,218 +0,0 @@ -import * as S from '../syntax/index.js'; -import { Substitution } from '../syntax/index.js'; -import * as G from './grammar.js'; -import { BootProc } from './internals.js'; - -export function stripShebang(items: S.Items): S.Items { - if ((items.length > 0) && - S.isToken(items[0]) && - items[0].text.startsWith('#!')) { - while (items.length > 0 && !S.isTokenType(items[0], S.TokenType.NEWLINE)) items.shift(); - } - return items; -} - -export interface CompileOptions { - source: string, - name?: string, - runtime?: string, - module?: 'es6' | 'require' | 'global', - global?: string, -} - -export interface CompilerOutput { - text: string, - map: S.SourceMap, -} - -export function compile(options: CompileOptions): CompilerOutput { - const inputFilename = options.name ?? '/dev/stdin'; - const source = options.source; - const moduleType = options.module ?? 'es6'; - - const scanner = new S.StringScanner(S.startPos(inputFilename), source); - const reader = new S.LaxReader(scanner); - let tree = stripShebang(reader.readToEnd()); - let macro = new S.Templates(); - - const runtime = options.runtime ?? '@syndicate/core'; - switch (moduleType) { - case 'es6': - tree = macro.template()`import * as __SYNDICATE__ from ${JSON.stringify(runtime)};\n${tree}`; - break; - case 'require': - tree = macro.template()`const __SYNDICATE__ = require(${JSON.stringify(runtime)});\n${tree}`; - break; - case 'global': - tree = macro.template()`const __SYNDICATE__ = ${runtime};\n${tree}`; - break; - } - - let passNumber = 0; - let expansionNeeded = true; - function expand(p: S.Pattern, f: (t: T) => S.Items) { - tree = S.replace(tree, p, t => { - expansionNeeded = true; - return f(t); - }); - } - - function receiverFor(s: G.FacetAction): Substitution { - return (s.implicitFacet) ? 'thisFacet.' : '.'; - } - - function expandFacetAction(p: S.Pattern, f: (t: T) => S.Items) { - expand(p, t => macro.template()`${receiverFor(t)}${f(t)}`); - } - - function terminalWrap(isTerminal: boolean, body: G.Statement): G.Statement { - if (isTerminal) { - return macro.template()`thisFacet._stop(function (thisFacet) {${body}})` - } else { - return body; - } - } - - while (expansionNeeded) { - if (++passNumber >= 128) { - throw new Error(`Too many compiler passes (${passNumber})!`); - } - - // console.log(`\n\n\n======================================== PASS ${passNumber}\n`); - // console.log(S.itemText(tree, { color: true, missing: '\x1b[41m□\x1b[0m' })); - - expansionNeeded = false; - expandFacetAction( - G.spawn, - s => { - let proc = macro.template()`function (thisFacet) {${s.bootProcBody}}`; - if (s.isDataspace) proc = macro.template()`__SYNDICATE__.inNestedDataspace(${proc})`; - let assertions = (s.initialAssertions.length > 0) - ? macro.template()`, new __SYNDICATE__.Set([${S.commaJoin(s.initialAssertions)}])` - : ``; - return macro.template()`_spawn(${s.name ?? 'null'}, ${proc}${assertions});`; - }); - expandFacetAction( - G.fieldDeclarationStatement, - s => { - const prop = ('name' in s.property) - ? [ { start: s.property.name.start, - end: s.property.name.end, - type: S.TokenType.STRING, - text: JSON.stringify(s.property.name.text) } ] - : s.property.expr; - return macro.template()`declareField(${s.target}, ${prop}, ${s.init ?? 'void 0'});`; - }); - expandFacetAction( - G.assertionEndpointStatement, - s => { - if (s.test == void 0) { - return macro.template()`addEndpoint(thisFacet => ({ assertion: ${s.template}, analysis: null }));`; - } else { - return macro.template()`addEndpoint(thisFacet => (${s.test ?? 'true'}) - ? ({ assertion: ${s.template}, analysis: null }) - : ({ assertion: void 0, analysis: null }), ${''+s.isDynamic});`; - } - }); - expandFacetAction( - G.dataflowStatement, - s => macro.template()`addDataflow(function (thisFacet) {${s.body}});`); - expandFacetAction( - G.eventHandlerEndpointStatement, - s => { - switch (s.triggerType) { - case 'dataflow': - return macro.template()`withSelfDo(function (thisFacet) { dataflow { if (${s.predicate}) { ${terminalWrap(s.terminal, s.body)} } } });`; - - case 'start': - case 'stop': { - const m = s.triggerType === 'start' ? 'addStartScript' : 'addStopScript'; - return macro.template()`${m}(function (thisFacet) {${s.body}});`; - } - - case 'asserted': - case 'retracted': - case 'message': { - const sa = G.compilePattern(s.pattern); - const expectedEvt = ({ - 'asserted': 'ADDED', - 'retracted': 'REMOVED', - 'message': 'MESSAGE', - })[s.triggerType]; - return macro.template()`addEndpoint(thisFacet => ({ - assertion: __SYNDICATE__.Observe(${sa.assertion}), - analysis: { - skeleton: ${sa.skeleton}, - constPaths: ${JSON.stringify(sa.constPaths)}, - constVals: [${S.commaJoin(sa.constVals)}], - capturePaths: ${JSON.stringify(sa.capturePaths)}, - callback: thisFacet.wrap((thisFacet, __Evt, [${S.commaJoin(sa.captureIds.map(i=>[i]))}]) => { - if (__Evt === __SYNDICATE__.Skeleton.EventType.${expectedEvt}) { - thisFacet.scheduleScript(() => {${terminalWrap(s.terminal, s.body)}}); - } - }) - } -}), ${'' + s.isDynamic});`; - } - } - }); - expandFacetAction( - G.duringStatement, - s => { - // TODO: spawn during - const sa = G.compilePattern(s.pattern); - return macro.template()`withSelfDo(function (thisFacet) { - const _Facets = new __SYNDICATE__.Dictionary(); - on asserted ${G.patternText(s.pattern)} => react { - _Facets.set([${S.commaJoin(sa.captureIds.map(t=>[t]))}], thisFacet); - dataflow void 0; // TODO: horrible hack to keep the facet alive if no other endpoints - ${s.body} - } - on retracted ${G.patternText(s.pattern)} => { - const _Key = [${S.commaJoin(sa.captureIds.map(t=>[t]))}]; - _Facets.get(_Key)._stop(); - _Facets.delete(_Key); - } -});`; - }); - expand( - G.typeDefinitionStatement, - s => { - const l = JSON.stringify(s.label.text); - const fs = JSON.stringify(s.fields.map(f => f.text)); - return macro.template()`const ${[s.label]} = __SYNDICATE__.Record.makeConstructor(${s.wireName ?? l}, ${fs});`; - }); - expandFacetAction( - G.messageSendStatement, - s => macro.template()`_send(${s.expr});`); - expandFacetAction( - G.reactStatement, - s => macro.template()`addChildFacet(function (thisFacet) {${s.body}});`); - expand( - G.bootStatement, - s => { - switch (moduleType) { - case 'es6': - return macro.template()`export function ${BootProc}(thisFacet) {${s}}`; - case 'global': - return macro.template()`module.exports.${BootProc} = function (thisFacet) {${s}};`; - case 'require': - return macro.template()`function ${BootProc}(thisFacet) {${s}}`; - } - }); - expandFacetAction( - G.stopStatement, - s => macro.template()`_stop(function (thisFacet) {${s.body}});`); - } - - // console.log(`\n\n\n======================================== FINAL OUTPUT\n`); - // console.log(S.itemText(tree)); - - const cw = new S.CodeWriter(inputFilename); - cw.emit(tree); - - return { - text: cw.text, - map: cw.map, - }; -} diff --git a/packages/core/src/compiler/internals.ts b/packages/core/src/compiler/internals.ts deleted file mode 100644 index 8602ef7..0000000 --- a/packages/core/src/compiler/internals.ts +++ /dev/null @@ -1 +0,0 @@ -export const BootProc = '__SYNDICATE__bootProc'; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c22e2e2..da0b36d 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -28,9 +28,6 @@ export * from './runtime/ground.js'; export * from './runtime/relay.js'; // export * as Worker from './runtime/worker.js'; -export * as Syntax from './syntax/index.js'; -export * as Compiler from './compiler/index.js'; - import { randomId } from './runtime/randomid.js'; // These aren't so much "Universal" as they are "VM-wide-unique". diff --git a/packages/core/src/runtime/api.ts b/packages/core/src/runtime/api.ts index 48b7d8f..251d981 100644 --- a/packages/core/src/runtime/api.ts +++ b/packages/core/src/runtime/api.ts @@ -1,3 +1,5 @@ +// Keep these definitions in sync with internals.ts from the compiler package +// export type NonEmptySkeleton = { shape: Shape, members: Skeleton[] }; export type Skeleton = null | NonEmptySkeleton; export type Path = Array; diff --git a/packages/core/src/runtime/ground.ts b/packages/core/src/runtime/ground.ts index 6a3a54b..4aad3a0 100644 --- a/packages/core/src/runtime/ground.ts +++ b/packages/core/src/runtime/ground.ts @@ -26,8 +26,6 @@ declare global { } } -const _resolved = Promise.resolve(); - export class Ground extends Dataspace { stepScheduled = false; stepping = false; @@ -42,16 +40,17 @@ export class Ground extends Dataspace { } } - static async laterCall(thunk: () => void): Promise { - await _resolved; - if ('stackTraceLimit' in Error) { - (Error as any).stackTraceLimit = 100; - } - try { - thunk(); - } catch (e) { - console.error("SYNDICATE/JS INTERNAL ERROR", e); - } + static laterCall(thunk: () => void): void { + queueMicrotask(() => { + if ('stackTraceLimit' in Error) { + (Error as any).stackTraceLimit = 100; + } + try { + thunk(); + } catch (e) { + console.error("SYNDICATE/JS INTERNAL ERROR", e); + } + }); } backgroundTask(): () => void { @@ -119,3 +118,11 @@ export class Ground extends Dataspace { // if (k) k(g); // } +export function bootModule(bootProc: Script): void { + const g = new Ground(bootProc); + if (typeof document !== 'undefined') { + document.addEventListener('DOMContentLoaded', () => g.start()); + } else { + g.start(); + } +} diff --git a/packages/core/src/syntax/position.ts b/packages/core/src/syntax/position.ts deleted file mode 100644 index 83551aa..0000000 --- a/packages/core/src/syntax/position.ts +++ /dev/null @@ -1,32 +0,0 @@ -export interface Pos { - line: number; - column: number; - pos: number; - name: string | null; -} - -export function startPos(name: string | null): Pos { - return { line: 1, column: 0, pos: 0, name }; -} - -export function advancePos(p: Pos, ch: string): boolean { - let advancedLine = false; - p.pos++; - switch (ch) { - case '\t': - p.column = (p.column + 8) & ~7; - break; - case '\n': - p.column = 0; - p.line++; - advancedLine = true; - break; - case '\r': - p.column = 0; - break; - default: - p.column++; - break; - } - return advancedLine; -} diff --git a/packages/syndicatec/LICENCE b/packages/syndicatec/LICENCE new file mode 120000 index 0000000..725d276 --- /dev/null +++ b/packages/syndicatec/LICENCE @@ -0,0 +1 @@ +gpl-3.0.txt \ No newline at end of file diff --git a/packages/syndicatec/Makefile b/packages/syndicatec/Makefile new file mode 120000 index 0000000..0e892c3 --- /dev/null +++ b/packages/syndicatec/Makefile @@ -0,0 +1 @@ +../../Makefile.generic-package \ No newline at end of file diff --git a/packages/syndicatec/bin/syndicatec.js b/packages/syndicatec/bin/syndicatec.js new file mode 100755 index 0000000..7ae4eb0 --- /dev/null +++ b/packages/syndicatec/bin/syndicatec.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib/index.js').main(process.argv.slice(2)); diff --git a/packages/syndicatec/examples/javascript/.gitignore b/packages/syndicatec/examples/javascript/.gitignore new file mode 100644 index 0000000..012a3cd --- /dev/null +++ b/packages/syndicatec/examples/javascript/.gitignore @@ -0,0 +1 @@ +index.js diff --git a/packages/syndicatec/examples/javascript/index.syndicate.js b/packages/syndicatec/examples/javascript/index.syndicate.js new file mode 100755 index 0000000..81fa28e --- /dev/null +++ b/packages/syndicatec/examples/javascript/index.syndicate.js @@ -0,0 +1,42 @@ +//--------------------------------------------------------------------------- +// @syndicate-lang/core, an implementation of Syndicate dataspaces for JS. +// Copyright (C) 2016-2021 Tony Garnock-Jones +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +//--------------------------------------------------------------------------- + +assertion type BoxState(value); +message type SetBox(newValue); + +const N = 100000; + +console.time('box-and-client-' + N.toString()); + +boot { + spawn named 'box' { + field this.value = 0; + assert BoxState(this.value); + stop on (this.value === N) + console.log('terminated box root facet'); + on message SetBox($v) => this.value = v; + } + + spawn named 'client' { + on asserted BoxState($v) => send message SetBox(v + 1); + on retracted BoxState(_) => console.log('box gone'); + } + + thisFacet.actor.dataspace.addStopHandler(() => + console.timeEnd('box-and-client-' + N.toString())); +} diff --git a/packages/syndicatec/examples/javascript/package.json b/packages/syndicatec/examples/javascript/package.json new file mode 100644 index 0000000..be3df28 --- /dev/null +++ b/packages/syndicatec/examples/javascript/package.json @@ -0,0 +1,19 @@ +{ + "name": "@syndicate-lang/syndicatec-javascript-example", + "version": "0.0.0", + "description": "Simple syndicatec example", + "main": "index.js", + "scripts": { + "prepare": "npm run compile", + "compile": "npx syndicatec -o index.js --module require index.syndicate.js", + "clean": "rm -f index.js" + }, + "author": "Tony Garnock-Jones ", + "license": "GPL-3.0+", + "dependencies": { + "@syndicate-lang/core": "file:../../../core" + }, + "devDependencies": { + "@syndicate-lang/syndicatec": "file:../.." + } +} diff --git a/packages/syndicatec/gpl-3.0.txt b/packages/syndicatec/gpl-3.0.txt new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/packages/syndicatec/gpl-3.0.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/packages/syndicatec/package.json b/packages/syndicatec/package.json new file mode 100644 index 0000000..f450e6b --- /dev/null +++ b/packages/syndicatec/package.json @@ -0,0 +1,27 @@ +{ + "name": "@syndicate-lang/syndicatec", + "version": "0.0.1", + "description": "Syndicate/JS compiler command-line tool", + "homepage": "https://github.com/syndicate-lang/syndicate-js/tree/master/packages/syndicatec", + "license": "GPL-3.0+", + "publishConfig": { + "access": "public" + }, + "repository": "github:syndicate-lang/syndicate-js", + "scripts": { + "prepare": "npm run compile", + "compile": "../../node_modules/.bin/tsc" + }, + "author": "Tony Garnock-Jones ", + "dependencies": { + "@syndicate-lang/compiler": "file:../compiler", + "@syndicate-lang/core": "file:../core", + "yargs": "^16.2.0" + }, + "bin": { + "syndicatec": "./bin/syndicatec.js" + }, + "devDependencies": { + "@types/yargs": "^15.0.12" + } +} diff --git a/packages/syndicatec/src/cli.ts b/packages/syndicatec/src/cli.ts new file mode 100644 index 0000000..3a1d858 --- /dev/null +++ b/packages/syndicatec/src/cli.ts @@ -0,0 +1,95 @@ +import yargs from 'yargs/yargs'; +import { Argv } from 'yargs'; + +import fs from 'fs'; +import { compile } from '@syndicate-lang/compiler'; + +export type ModuleChoice = 'es6' | 'require' | 'global'; +const moduleChoices: ReadonlyArray = ['es6', 'require', 'global']; + +export type CommandLineArguments = { + input: string | undefined; + output: string | undefined; + map: boolean; + mapExtension?: string; + runtime: string; + module: ModuleChoice; +} + +function checkModuleChoice(t: T & { module: string }): T & { module: ModuleChoice } { + const mc = t.module as ModuleChoice; + if (moduleChoices.indexOf(mc) !== -1) return { ... t, module: mc }; + throw new Error("Illegal --module argument: " + t.module); +} + +export function main(argv: string[]) { + const options: CommandLineArguments = checkModuleChoice(yargs(argv) + .command('$0 [input]', + 'Compile a single file', + yargs => yargs + .positional('input', { + type: 'string', + description: 'Input filename', + }) + .option('output', { + alias: 'o', + type: 'string', + description: 'Output filename (stdout if omitted)', + }) + .option('map', { + type: 'boolean', + description: 'Generate source maps', + default: true, + }) + .option('map-extension', { + type: 'string', + description: 'Extension (e.g. ".map") to add to source map files; if omitted, source maps are generated inline', + }) + .option('runtime', { + type: 'string', + description: 'Path to require or import to get the Syndicate runtime', + default: '@syndicate-lang/core', + }) + .option('module', { + choices: moduleChoices, + type: 'string', + description: 'Style of import/export definition to prefer', + default: moduleChoices[0], + }), + argv => argv) + .argv); + + const inputFilename = options.input ?? '/dev/stdin'; + const source = fs.readFileSync(inputFilename, 'utf-8'); + + const { text, map } = compile({ + source, + name: inputFilename, + runtime: options.runtime, + module: options.module, + }); + map.sourcesContent = [source]; + + function mapDataURL() { + const mapData = Buffer.from(JSON.stringify(map)).toString('base64') + return `data:application/json;base64,${mapData}`; + } + + if (options.output !== void 0) { + if (!options.map) { + fs.writeFileSync(options.output, text); + } else if (options.mapExtension) { + const mapFilename = options.output + options.mapExtension; + fs.writeFileSync(options.output, text + `\n//# sourceMappingURL=${mapFilename}`); + fs.writeFileSync(mapFilename, JSON.stringify(map)); + } else { + fs.writeFileSync(options.output, text + `\n//# sourceMappingURL=${mapDataURL()}`); + } + } else { + if (!options.map) { + console.log(text); + } else { + console.log(text + `\n//# sourceMappingURL=${mapDataURL()}`); + } + } +} diff --git a/packages/syndicatec/src/index.ts b/packages/syndicatec/src/index.ts new file mode 100644 index 0000000..c01c2dc --- /dev/null +++ b/packages/syndicatec/src/index.ts @@ -0,0 +1 @@ +export * from './cli.js'; diff --git a/packages/syndicatec/tsconfig.json b/packages/syndicatec/tsconfig.json new file mode 100644 index 0000000..abc7c03 --- /dev/null +++ b/packages/syndicatec/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["ES2017", "DOM"], + "declaration": true, + "baseUrl": "./src", + "rootDir": "./src", + "outDir": "./lib", + "declarationDir": "./lib", + "esModuleInterop": true, + "moduleResolution": "node", + "module": "commonjs", + "sourceMap": true, + "strict": true + }, + "include": ["src/**/*"] +}