diff --git a/.pylintrc b/.pylintrc
index 0ad0f52..fd79244 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -102,6 +102,9 @@ disable=raw-checker-failed,
too-many-return-statements,
# Let me have my locals dangit :(
too-many-locals,
+ # PyCharm's detection is smarter and takes child classes overriding
+ # the method into account
+ no-self-use,
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
diff --git a/README.md b/README.md
index d3e6f74..f4ed773 100644
--- a/README.md
+++ b/README.md
@@ -58,3 +58,8 @@ Zoia itself is licensed [under the GPLv3](LICENSE).
This does not extend to fiction you write using it, nor does it extend to
the output generated from such fiction once Zoia compiles it. You may
license such data however you like.
+
+Note that some files in this repository are licensed under other licenses.
+None of them are part of Zoia itself, they function purely as examples.
+See the [examples directory](doc/examples) and the LICENSE files in there for
+more information.
diff --git a/doc/examples/othello/LICENSE b/doc/examples/othello/LICENSE
new file mode 100644
index 0000000..00963cb
--- /dev/null
+++ b/doc/examples/othello/LICENSE
@@ -0,0 +1,70 @@
+CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.
+
+License
+
+THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+
+BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
+
+1. Definitions
+
+ "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License.
+ "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License.
+ "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership.
+ "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.
+ "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast.
+ "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work.
+ "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
+ "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.
+ "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium.
+
+2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws.
+
+3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
+
+ to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections;
+ to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified.";
+ to Distribute and Publicly Perform the Work including as incorporated in Collections; and,
+ to Distribute and Publicly Perform Adaptations.
+
+The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Section 4(d).
+
+4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
+
+ You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested.
+ You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works.
+ If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.
+
+ For the avoidance of doubt:
+ Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;
+ Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and,
+ Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c).
+ Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise.
+
+5. Representations, Warranties and Disclaimer
+
+UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
+
+6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. Termination
+
+ This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
+ Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
+
+8. Miscellaneous
+
+ Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
+ Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
+ If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
+ No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
+ This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
+ The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law.
+
+Creative Commons Notice
+
+Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor.
+
+Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of the License.
+
+Creative Commons may be contacted at https://creativecommons.org/.
diff --git a/doc/examples/othello/src/aliases.zoia b/doc/examples/othello/src/aliases.zoia
new file mode 100644
index 0000000..3fdcd09
--- /dev/null
+++ b/doc/examples/othello/src/aliases.zoia
@@ -0,0 +1,13 @@
+\header[aliases]
+
+\def_alias[B; Brabantio]
+\def_alias[BI; Bianca]
+\def_alias[C; Cassio]
+\def_alias[D; Desdemona]
+\def_alias[E; Emilia]
+\def_alias[G; Gratiano]
+\def_alias[I; Iago]
+\def_alias[L; Lodovico]
+\def_alias[M; Montano]
+\def_alias[O; Othello]
+\def_alias[R; Roderigo]
diff --git a/doc/examples/othello/src/dictionary.zoia b/doc/examples/othello/src/dictionary.zoia
new file mode 100644
index 0000000..5f061cc
--- /dev/null
+++ b/doc/examples/othello/src/dictionary.zoia
@@ -0,0 +1 @@
+\header[dictionary]
diff --git a/doc/examples/othello/src/work1/ch1/main.zoia b/doc/examples/othello/src/work1/ch1/main.zoia
new file mode 100644
index 0000000..c67d663
--- /dev/null
+++ b/doc/examples/othello/src/work1/ch1/main.zoia
@@ -0,0 +1,5776 @@
+\header[chapter]
+
+# We want to insert line breaks after every line of text down below
+\eol_behavior[break]
+
+\title[Othello]
+\author[William Shakespeare]
+\editor[
+ Barbara A. Mowat;
+ Paul Werstine;
+ Michael Poston;
+ Rebecca Niles;
+]
+\homepage[https://shakespeare.folger.edu/shakespeares-works/othello/]
+\license[
+ code = CC-BY-NC-3.0;
+ link = https://shakespeare.folger.edu/terms-of-use/;
+ notes = Modified to fit Zoia format;
+]
+
+\begin_work_summary
+A rudimentary port of Othello to Zoia.
+\end_work_summary
+
+\begin_characters
+\character[
+ @O|;
+ A Moorish general in the Venetian army;
+]
+\character[
+ @D|;
+ A Venetian lady;
+]
+\character[
+ @B|;
+ A Venetian senator, father to @D|;
+]
+\character[
+ @I|;
+ @O|'s standard-bearer, or "ancient";
+]
+\character[
+ @E|;
+ @I|'s wife and @D|'s attendant;
+]
+\character[
+ @C|;
+ @O|'s second-in-command, or lieutenant;
+]
+\character[
+ @R|;
+ A Venetian gentleman;
+]
+\character[Duke of Venice]
+\character[
+ @L|;
+ Venetian gentleman, kinsman to @B|;
+]
+\character[
+ @G|;
+ Venetian gentleman, kinsman to @B|;
+]
+\character[Venetian senators]
+\character[
+ @M|;
+ An official in Cyprus
+]
+\character[
+ @BI|;
+ A woman in Cyprus in love with @C|;
+]
+\character[
+ Clown;
+ A comic servant to @O| and @D|;
+]
+\character[Gentlemen of Cyprus]
+\character[Sailors]
+\character[Servants]
+\character[Attendants]
+\character[Officers]
+\character[Messengers]
+\character[Herald]
+\character[Musicians]
+\character[Torchbearers]
+\end_characters
+
+\h1[Act 1]
+
+\h2[Scene 1]
+
+\lbracket|Enter @R| and @I|.\rbracket|
+
+**@R|**
+Tush, never tell me! I take it much unkindly
+That thou, @I|, who hast had my purse
+As if the strings were thine, shouldst know of this.
+
+**@I|** 'Sblood, but you'll not hear me!
+If ever I did dream of such a matter,
+Abhor me.
+
+**@R|**
+Thou toldst me thou didst hold him in thy hate.
+
+**@I|** Despise me
+If I do not. Three great ones of the city,
+In personal suit to make me his lieutenant,
+Off-capped to him\semicolon| and, by the faith of man,
+I know my price, I am worth no worse a place.
+But he, as loving his own pride and purposes,
+Evades them with a bombast circumstance,
+Horribly stuffed with epithets of war,
+And in conclusion,
+Nonsuits my mediators. For "Certes," says he,
+"I have already chose my officer."
+And what was he?
+Forsooth, a great arithmetician,
+One Michael @C|, a Florentine,
+A fellow almost damned in a fair wife,
+That never set a squadron in the field,
+Nor the division of a battle knows
+More than a spinster--unless the bookish theoric,
+Wherein the toged consuls can propose
+As masterly as he. Mere prattle without practice
+Is all his soldiership. But he, sir, had th' election\semicolon|
+And I, of whom his eyes had seen the proof
+At Rhodes, at Cyprus, and on other grounds
+Christened and heathen, must be beleed and
+calmed
+By debitor and creditor. This countercaster,
+He, in good time, must his lieutenant be,
+And I, God bless the mark, his Moorship's ancient.
+
+**@R|**
+By heaven, I rather would have been his hangman.
+
+**@I|**
+Why, there's no remedy. 'Tis the curse of service.
+Preferment goes by letter and affection,
+And not by old gradation, where each second
+Stood heir to th' first. Now, sir, be judge yourself
+Whether I in any just term am affined
+To love the Moor.
+
+**@R|**
+I would not follow him, then.
+
+**@I|** O, sir, content you.
+I follow him to serve my turn upon him.
+We cannot all be masters, nor all masters
+Cannot be truly followed. You shall mark
+Many a duteous and knee-crooking knave
+That, doting on his own obsequious bondage,
+Wears out his time, much like his master's ass,
+For naught but provender, and when he's old,
+cashiered.
+Whip me such honest knaves! Others there are
+Who, trimmed in forms and visages of duty,
+Keep yet their hearts attending on themselves,
+And, throwing but shows of service on their lords,
+Do well thrive by them\semicolon| and when they have lined
+their coats,
+Do themselves homage. These fellows have some
+soul,
+And such a one do I profess myself. For, sir,
+It is as sure as you are @R|,
+Were I the Moor I would not be @I|.
+In following him, I follow but myself.
+Heaven is my judge, not I for love and duty,
+But seeming so for my peculiar end.
+For when my outward action doth demonstrate
+The native act and figure of my heart
+In complement extern, 'tis not long after
+But I will wear my heart upon my sleeve
+For daws to peck at. I am not what I am.
+
+**@R|**
+What a full fortune does the thick-lips owe
+If he can carry 't thus!
+
+**@I|** Call up her father.
+Rouse him. Make after him, poison his delight,
+Proclaim him in the streets\semicolon| incense her kinsmen,
+And, though he in a fertile climate dwell,
+Plague him with flies. Though that his joy be joy,
+Yet throw such chances of vexation on 't
+As it may lose some color.
+
+**@R|**
+Here is her father's house. I'll call aloud.
+
+**@I|**
+Do, with like timorous accent and dire yell
+As when, by night and negligence, the fire
+Is spied in populous cities.
+
+**@R|**
+What ho, @B|! Signior @B|, ho!
+
+**@I|**
+Awake! What ho, @B|! Thieves, thieves!
+Look to your house, your daughter, and your bags!
+Thieves, thieves!
+
+\lbracket|Enter @B|, above.\rbracket|
+
+
+**@B|**
+What is the reason of this terrible summons?
+What is the matter there?
+
+**@R|**
+Signior, is all your family within?
+
+**@I|**
+Are your doors locked?
+
+**@B|** Why, wherefore ask you this?
+
+**@I|**
+Zounds, sir, you're robbed. For shame, put on your
+gown!
+Your heart is burst. You have lost half your soul.
+Even now, now, very now, an old black ram
+Is tupping your white ewe. Arise, arise!
+Awake the snorting citizens with the bell,
+Or else the devil will make a grandsire of you.
+Arise, I say!
+
+**@B|** What, have you lost your wits?
+
+**@R|**
+Most reverend signior, do you know my voice?
+
+**@B|** Not I. What are you?
+
+**@R|**
+My name is @R|.
+
+**@B|** The worser welcome.
+I have charged thee not to haunt about my doors.
+In honest plainness thou hast heard me say
+My daughter is not for thee. And now in madness,
+Being full of supper and distemp'ring draughts,
+Upon malicious bravery dost thou come
+To start my quiet.
+
+**@R|** Sir, sir, sir--
+
+**@B|** But thou must needs be sure
+My spirit and my place have in them power
+To make this bitter to thee.
+
+**@R|**
+Patience, good sir.
+
+**@B|** What tell'st thou me of robbing?
+This is Venice. My house is not a grange.
+
+**@R|** Most grave @B|,
+In simple and pure soul I come to you--
+
+**@I|** Zounds, sir, you are one of those that will not
+serve God if the devil bid you. Because we come to
+do you service and you think we are ruffians, you'll
+have your daughter covered with a Barbary horse,
+you'll have your nephews neigh to you, you'll have
+coursers for cousins and jennets for germans.
+
+**@B|** What profane wretch art thou?
+
+**@I|** I am one, sir, that comes to tell you your daughter
+and the Moor are now making the beast with
+two backs.
+
+**@B|** Thou art a villain.
+
+**@I|** You are a senator.
+
+**@B|**
+This thou shalt answer. I know thee, @R|.
+
+**@R|**
+Sir, I will answer anything. But I beseech you,
+If 't be your pleasure and most wise consent--
+As partly I find it is--that your fair daughter,
+At this odd-even and dull watch o' th' night,
+Transported with no worse nor better guard
+But with a knave of common hire, a gondolier,
+To the gross clasps of a lascivious Moor:
+If this be known to you, and your allowance,
+We then have done you bold and saucy wrongs.
+But if you know not this, my manners tell me
+We have your wrong rebuke. Do not believe
+That from the sense of all civility
+I thus would play and trifle with your Reverence.
+Your daughter, if you have not given her leave,
+I say again, hath made a gross revolt,
+Tying her duty, beauty, wit, and fortunes
+In an extravagant and wheeling stranger
+Of here and everywhere. Straight satisfy yourself.
+If she be in her chamber or your house,
+Let loose on me the justice of the state
+For thus deluding you.
+
+**@B|** Strike on the tinder, ho!
+Give me a taper. Call up all my people.
+This accident is not unlike my dream.
+Belief of it oppresses me already.
+Light, I say, light! \lbracket|He exits.\rbracket|
+
+**@I|**, \lbracket|to @R|\rbracket| Farewell, for I must leave you.
+It seems not meet nor wholesome to my place
+To be producted, as if I stay I shall,
+Against the Moor. For I do know the state,
+However this may gall him with some check,
+Cannot with safety cast him, for he's embarked
+With such loud reason to the Cyprus wars,
+Which even now stands in act, that, for their souls,
+Another of his fathom they have none
+To lead their business. In which regard,
+Though I do hate him as I do hell pains,
+Yet, for necessity of present life,
+I must show out a flag and sign of love--
+Which is indeed but sign. That you shall surely find
+him,
+Lead to the Sagittary the raised search,
+And there will I be with him. So, farewell. \lbracket|He exits.\rbracket|
+
+\lbracket|Enter @B| in his nightgown, with Servants and
+Torches.\rbracket|
+
+
+**@B|**
+It is too true an evil. Gone she is,
+And what's to come of my despised time
+Is naught but bitterness.--Now, @R|,
+Where didst thou see her?--O, unhappy girl!--
+With the Moor, sayst thou?--Who would be a
+father?--
+How didst thou know 'twas she?--O, she deceives
+me
+Past thought!--What said she to you?--Get more
+tapers.
+Raise all my kindred.--Are they married, think
+you?
+
+**@R|** Truly, I think they are.
+
+**@B|**
+O heaven! How got she out? O treason of the blood!
+Fathers, from hence trust not your daughters' minds
+By what you see them act.--Is there not charms
+By which the property of youth and maidhood
+May be abused? Have you not read, @R|,
+Of some such thing?
+
+**@R|** Yes, sir, I have indeed.
+
+**@B|**
+Call up my brother.--O, would you had had her!--
+Some one way, some another.--Do you know
+Where we may apprehend her and the Moor?
+
+**@R|**
+I think I can discover him, if you please
+To get good guard and go along with me.
+
+**@B|**
+Pray you lead on. At every house I'll call.
+I may command at most.--Get weapons, ho!
+And raise some special officers of night.--
+On, good @R|. I will deserve your pains.
+\lbracket|They exit.\rbracket|
+
+\h2[Scene 2]
+
+\lbracket|Enter @O|, @I|, Attendants, with Torches.\rbracket|
+
+
+**@I|**
+Though in the trade of war I have slain men,
+Yet do I hold it very stuff o' th' conscience
+To do no contrived murder. I lack iniquity
+Sometimes to do me service. Nine or ten times
+I had thought t' have yerked him here under the
+ribs.
+
+**@O|**
+'Tis better as it is.
+
+**@I|** Nay, but he prated
+And spoke such scurvy and provoking terms
+Against your Honor,
+That with the little godliness I have
+I did full hard forbear him. But I pray you, sir,
+Are you fast married? Be assured of this,
+That the magnifico is much beloved,
+And hath in his effect a voice potential
+As double as the Duke's. He will divorce you
+Or put upon you what restraint or grievance
+The law (with all his might to enforce it on)
+Will give him cable.
+
+**@O|** Let him do his spite.
+My services which I have done the signiory
+Shall out-tongue his complaints. 'Tis yet to know
+(Which, when I know that boasting is an honor,
+I shall promulgate) I fetch my life and being
+From men of royal siege, and my demerits
+May speak unbonneted to as proud a fortune
+As this that I have reached. For know, @I|,
+But that I love the gentle @D|,
+I would not my unhoused free condition
+Put into circumscription and confine
+For the sea's worth. But look, what lights come
+yond?
+
+**@I|**
+Those are the raised father and his friends.
+You were best go in.
+
+**@O|** Not I. I must be found.
+My parts, my title, and my perfect soul
+Shall manifest me rightly. Is it they?
+
+**@I|** By Janus, I think no.
+
+\lbracket|Enter @C|, with Officers, and Torches.\rbracket|
+
+
+**@O|**
+The servants of the Duke and my lieutenant!
+The goodness of the night upon you, friends.
+What is the news?
+
+**@C|** The Duke does greet you, general,
+And he requires your haste-post-haste appearance,
+Even on the instant.
+
+**@O|** What is the matter, think you?
+
+**@C|**
+Something from Cyprus, as I may divine.
+It is a business of some heat. The galleys
+Have sent a dozen sequent messengers
+This very night at one another's heels,
+And many of the Consuls, raised and met,
+Are at the Duke's already. You have been hotly
+called for.
+When, being not at your lodging to be found,
+The Senate hath sent about three several quests
+To search you out.
+
+**@O|** 'Tis well I am found by you.
+I will but spend a word here in the house
+And go with you. \lbracket|He exits.\rbracket|
+
+**@C|** Ancient, what makes he here?
+
+**@I|**
+Faith, he tonight hath boarded a land carrack.
+If it prove lawful prize, he's made forever.
+
+**@C|**
+I do not understand.
+
+**@I|** He's married.
+
+**@C|** To who?
+
+**@I|**
+Marry, to--
+
+\lbracket|Reenter @O|.\rbracket|
+
+Come, captain, will you go?
+
+**@O|** Have with you.
+
+**@C|**
+Here comes another troop to seek for you.
+
+\lbracket|Enter @B|, @R|, with Officers, and Torches.\rbracket|
+
+
+**@I|**
+It is @B|. General, be advised,
+He comes to bad intent.
+
+**@O|** Holla, stand there!
+
+**@R|**
+Signior, it is the Moor.
+
+**@B|** Down with him,
+thief!
+\lbracket|They draw their swords.\rbracket|
+
+**@I|**
+You, @R|! Come, sir, I am for you.
+
+**@O|**
+Keep up your bright swords, for the dew will rust
+them.
+Good signior, you shall more command with years
+Than with your weapons.
+
+**@B|**
+O, thou foul thief, where hast thou stowed my
+daughter?
+Damned as thou art, thou hast enchanted her!
+For I'll refer me to all things of sense,
+If she in chains of magic were not bound,
+Whether a maid so tender, fair, and happy,
+So opposite to marriage that she shunned
+The wealthy curled darlings of our nation,
+Would ever have, t' incur a general mock,
+Run from her guardage to the sooty bosom
+Of such a thing as thou--to fear, not to delight!
+Judge me the world, if 'tis not gross in sense
+That thou hast practiced on her with foul charms,
+Abused her delicate youth with drugs or minerals
+That weakens motion. I'll have 't disputed on.
+'Tis probable, and palpable to thinking.
+I therefore apprehend and do attach thee
+For an abuser of the world, a practicer
+Of arts inhibited and out of warrant.--
+Lay hold upon him. If he do resist,
+Subdue him at his peril.
+
+**@O|** Hold your hands,
+Both you of my inclining and the rest.
+Were it my cue to fight, I should have known it
+Without a prompter.--Whither will you that I go
+To answer this your charge?
+
+**@B|** To prison, till fit time
+Of law and course of direct session
+Call thee to answer.
+
+**@O|** What if I do obey?
+How may the Duke be therewith satisfied,
+Whose messengers are here about my side,
+Upon some present business of the state,
+To bring me to him?
+
+**OFFICER** 'Tis true, most worthy signior.
+The Duke's in council, and your noble self
+I am sure is sent for.
+
+**@B|** How? The Duke in council?
+In this time of the night? Bring him away\semicolon|
+Mine's not an idle cause. The Duke himself,
+Or any of my brothers of the state,
+Cannot but feel this wrong as 'twere their own.
+For if such actions may have passage free,
+Bondslaves and pagans shall our statesmen be.
+\lbracket|They exit.\rbracket|
+
+\h2[Scene 3]
+
+\lbracket|Enter Duke, Senators, and Officers.\rbracket|
+
+
+**DUKE**, \lbracket|reading a paper\rbracket|
+There's no composition in these news
+That gives them credit.
+
+**FIRST** **SENATOR**, \lbracket|reading a paper\rbracket|
+Indeed, they are disproportioned.
+My letters say a hundred and seven galleys.
+
+**DUKE**
+And mine, a hundred forty.
+
+**SECOND** **SENATOR**, \lbracket|reading a paper\rbracket|
+And mine, two hundred.
+But though they jump not on a just account
+(As in these cases, where the aim reports
+'Tis oft with difference), yet do they all confirm
+A Turkish fleet, and bearing up to Cyprus.
+
+**DUKE**
+Nay, it is possible enough to judgment.
+I do not so secure me in the error,
+But the main article I do approve
+In fearful sense.
+
+**SAILOR**, \lbracket|within\rbracket| What ho, what ho, what ho!
+
+\lbracket|Enter Sailor.\rbracket|
+
+
+**OFFICER** A messenger from the galleys.
+
+**DUKE** Now, what's the business?
+
+**SAILOR**
+The Turkish preparation makes for Rhodes.
+So was I bid report here to the state
+By Signior Angelo. \lbracket|He exits.\rbracket|
+
+**DUKE**
+How say you by this change?
+
+**FIRST** **SENATOR** This cannot be,
+By no assay of reason. 'Tis a pageant
+To keep us in false gaze. When we consider
+Th' importancy of Cyprus to the Turk,
+And let ourselves again but understand
+That, as it more concerns the Turk than Rhodes,
+So may he with more facile question bear it,
+For that it stands not in such warlike brace,
+But altogether lacks th' abilities
+That Rhodes is dressed in--if we make thought of
+this,
+We must not think the Turk is so unskillful
+To leave that latest which concerns him first,
+Neglecting an attempt of ease and gain
+To wake and wage a danger profitless.
+
+**DUKE**
+Nay, in all confidence, he's not for Rhodes.
+
+**OFFICER** Here is more news.
+
+\lbracket|Enter a Messenger.\rbracket|
+
+
+**MESSENGER**
+The Ottomites, Reverend and Gracious,
+Steering with due course toward the isle of Rhodes,
+Have there injointed them with an after fleet.
+
+**FIRST** **SENATOR**
+Ay, so I thought. How many, as you guess?
+
+**MESSENGER**
+Of thirty sail\semicolon| and now they do restem
+Their backward course, bearing with frank
+appearance
+Their purposes toward Cyprus. Signior @M|,
+Your trusty and most valiant servitor,
+With his free duty recommends you thus,
+And prays you to believe him. \lbracket|He exits.\rbracket|
+
+**DUKE** 'Tis certain, then, for Cyprus.
+Marcus Luccicos, is not he in town?
+
+**FIRST** **SENATOR**
+He's now in Florence.
+
+**DUKE** Write from us to him.
+Post-post-haste. Dispatch.
+
+**FIRST** **SENATOR**
+Here comes @B| and the valiant Moor.
+
+\lbracket|Enter @B|, @O|, @C|, @I|, @R|, and
+Officers.\rbracket|
+
+
+**DUKE**
+Valiant @O|, we must straight employ you
+Against the general enemy Ottoman.
+\lbracket|To @B|.\rbracket| I did not see you. Welcome, gentle
+signior.
+We lacked your counsel and your help tonight.
+
+**@B|**
+So did I yours. Good your Grace, pardon me.
+Neither my place nor aught I heard of business
+Hath raised me from my bed, nor doth the general
+care
+Take hold on me, for my particular grief
+Is of so floodgate and o'erbearing nature
+That it engluts and swallows other sorrows
+And it is still itself.
+
+**DUKE** Why, what's the matter?
+
+**@B|**
+My daughter! O, my daughter!
+
+**FIRST** **SENATOR** Dead?
+
+**@B|** Ay, to me.
+She is abused, stol'n from me, and corrupted
+By spells and medicines bought of mountebanks\semicolon|
+For nature so prepost'rously to err--
+Being not deficient, blind, or lame of sense--
+Sans witchcraft could not.
+
+**DUKE**
+Whoe'er he be that in this foul proceeding
+Hath thus beguiled your daughter of herself
+And you of her, the bloody book of law
+You shall yourself read in the bitter letter,
+After your own sense, yea, though our proper son
+Stood in your action.
+
+**@B|** Humbly I thank your Grace.
+Here is the man--this Moor, whom now it seems
+Your special mandate for the state affairs
+Hath hither brought.
+
+**ALL** We are very sorry for 't.
+
+**DUKE**, \lbracket|to @O|\rbracket|
+What, in your own part, can you say to this?
+
+**@B|** Nothing, but this is so.
+
+**@O|**
+Most potent, grave, and reverend signiors,
+My very noble and approved good masters:
+That I have ta'en away this old man's daughter,
+It is most true\semicolon| true I have married her.
+The very head and front of my offending
+Hath this extent, no more. Rude am I in my speech,
+And little blessed with the soft phrase of peace\semicolon|
+For since these arms of mine had seven years' pith,
+Till now some nine moons wasted, they have used
+Their dearest action in the tented field,
+And little of this great world can I speak
+More than pertains to feats of broil and battle.
+And therefore little shall I grace my cause
+In speaking for myself. Yet, by your gracious
+patience,
+I will a round unvarnished tale deliver
+Of my whole course of love--what drugs, what
+charms,
+What conjuration, and what mighty magic
+(For such proceeding I am charged withal)
+I won his daughter.
+
+**@B|** A maiden never bold,
+Of spirit so still and quiet that her motion
+Blushed at herself. And she, in spite of nature,
+Of years, of country, credit, everything,
+To fall in love with what she feared to look on!
+It is a judgment maimed and most imperfect
+That will confess perfection so could err
+Against all rules of nature, and must be driven
+To find out practices of cunning hell
+Why this should be. I therefore vouch again
+That with some mixtures powerful o'er the blood,
+Or with some dram conjured to this effect,
+He wrought upon her.
+
+**DUKE** To vouch this is no proof
+Without more wider and more overt test
+Than these thin habits and poor likelihoods
+Of modern seeming do prefer against him.
+
+**FIRST** **SENATOR** But, @O|, speak:
+Did you by indirect and forced courses
+Subdue and poison this young maid's affections?
+Or came it by request, and such fair question
+As soul to soul affordeth?
+
+**@O|** I do beseech you,
+Send for the lady to the Sagittary
+And let her speak of me before her father.
+If you do find me foul in her report,
+The trust, the office I do hold of you,
+Not only take away, but let your sentence
+Even fall upon my life.
+
+**DUKE** Fetch @D| hither.
+
+**@O|**
+Ancient, conduct them. You best know the place.
+\lbracket|@I| and Attendants exit.\rbracket|
+And till she come, as truly as to heaven
+I do confess the vices of my blood,
+So justly to your grave ears I'll present
+How I did thrive in this fair lady's love,
+And she in mine.
+
+**DUKE** Say it, @O|.
+
+**@O|**
+Her father loved me, oft invited me,
+Still questioned me the story of my life
+From year to year--the battles, sieges, fortunes
+That I have passed.
+I ran it through, even from my boyish days
+To th' very moment that he bade me tell it,
+Wherein I spoke of most disastrous chances:
+Of moving accidents by flood and field,
+Of hairbreadth 'scapes i' th' imminent deadly
+breach,
+Of being taken by the insolent foe
+And sold to slavery, of my redemption thence,
+And portance in my traveler's history,
+Wherein of antres vast and deserts idle,
+Rough quarries, rocks, and hills whose heads
+touch heaven,
+It was my hint to speak--such was my process--
+And of the cannibals that each other eat,
+The Anthropophagi, and men whose heads
+Do grow beneath their shoulders. These things to
+hear
+Would @D| seriously incline.
+But still the house affairs would draw her thence,
+Which ever as she could with haste dispatch
+She'd come again, and with a greedy ear
+Devour up my discourse. Which I, observing,
+Took once a pliant hour, and found good means
+To draw from her a prayer of earnest heart
+That I would all my pilgrimage dilate,
+Whereof by parcels she had something heard,
+But not intentively. I did consent,
+And often did beguile her of her tears
+When I did speak of some distressful stroke
+That my youth suffered. My story being done,
+She gave me for my pains a world of sighs.
+She swore, in faith, 'twas strange, 'twas passing
+strange,
+'Twas pitiful, 'twas wondrous pitiful.
+She wished she had not heard it, yet she wished
+That heaven had made her such a man. She thanked
+me,
+And bade me, if I had a friend that loved her,
+I should but teach him how to tell my story,
+And that would woo her. Upon this hint I spake.
+She loved me for the dangers I had passed,
+And I loved her that she did pity them.
+This only is the witchcraft I have used.
+Here comes the lady. Let her witness it.
+
+\lbracket|Enter @D|, @I|, Attendants.\rbracket|
+
+
+**DUKE**
+I think this tale would win my daughter, too.
+Good @B|,
+Take up this mangled matter at the best.
+Men do their broken weapons rather use
+Than their bare hands.
+
+**@B|** I pray you hear her speak.
+If she confess that she was half the wooer,
+Destruction on my head if my bad blame
+Light on the man.--Come hither, gentle mistress.
+Do you perceive in all this noble company
+Where most you owe obedience?
+
+**@D|** My noble father,
+I do perceive here a divided duty.
+To you I am bound for life and education.
+My life and education both do learn me
+How to respect you. You are the lord of duty.
+I am hitherto your daughter. But here's my
+husband.
+And so much duty as my mother showed
+To you, preferring you before her father,
+So much I challenge that I may profess
+Due to the Moor my lord.
+
+**@B|** God be with you! I have done.
+Please it your Grace, on to the state affairs.
+I had rather to adopt a child than get it.--
+Come hither, Moor.
+I here do give thee that with all my heart
+Which, but thou hast already, with all my heart
+I would keep from thee.--For your sake, jewel,
+I am glad at soul I have no other child,
+For thy escape would teach me tyranny,
+To hang clogs on them.--I have done, my lord.
+
+**DUKE**
+Let me speak like yourself and lay a sentence,
+Which as a grise or step may help these lovers
+Into your favor.
+When remedies are past, the griefs are ended
+By seeing the worst, which late on hopes depended.
+To mourn a mischief that is past and gone
+Is the next way to draw new mischief on.
+What cannot be preserved when fortune takes,
+Patience her injury a mock'ry makes.
+The robbed that smiles steals something from the
+thief\semicolon|
+He robs himself that spends a bootless grief.
+
+**@B|**
+So let the Turk of Cyprus us beguile,
+We lose it not so long as we can smile.
+He bears the sentence well that nothing bears
+But the free comfort which from thence he hears\semicolon|
+But he bears both the sentence and the sorrow
+That, to pay grief, must of poor patience borrow.
+These sentences to sugar or to gall,
+Being strong on both sides, are equivocal.
+But words are words. I never yet did hear
+That the bruised heart was pierced through the
+ear.
+I humbly beseech you, proceed to th' affairs of
+state.
+
+**DUKE** The Turk with a most mighty preparation makes
+for Cyprus. @O|, the fortitude of the place is
+best known to you. And though we have there a
+substitute of most allowed sufficiency, yet opinion, a
+sovereign mistress of effects, throws a more safer
+voice on you. You must therefore be content to
+slubber the gloss of your new fortunes with this
+more stubborn and boist'rous expedition.
+
+**@O|**
+The tyrant custom, most grave senators,
+Hath made the flinty and steel couch of war
+My thrice-driven bed of down. I do agnize
+A natural and prompt alacrity
+I find in hardness, and do undertake
+This present wars against the Ottomites.
+Most humbly, therefore, bending to your state,
+I crave fit disposition for my wife,
+Due reference of place and exhibition,
+With such accommodation and besort
+As levels with her breeding.
+
+**DUKE**
+Why, at her father's.
+
+**@B|** I will not have it so.
+
+**@O|** Nor I.
+
+**@D|** Nor would I there reside
+To put my father in impatient thoughts
+By being in his eye. Most gracious duke,
+To my unfolding lend your prosperous ear
+And let me find a charter in your voice
+T' assist my simpleness.
+
+**DUKE** What would you, @D|?
+
+**@D|**
+That I love the Moor to live with him
+My downright violence and storm of fortunes
+May trumpet to the world. My heart's subdued
+Even to the very quality of my lord.
+I saw @O|'s visage in his mind,
+And to his honors and his valiant parts
+Did I my soul and fortunes consecrate.
+So that, dear lords, if I be left behind,
+A moth of peace, and he go to the war,
+The rites for why I love him are bereft me
+And I a heavy interim shall support
+By his dear absence. Let me go with him.
+
+**@O|** Let her have your voice.
+Vouch with me, heaven, I therefore beg it not
+To please the palate of my appetite,
+Nor to comply with heat (the young affects
+In me defunct) and proper satisfaction,
+But to be free and bounteous to her mind.
+And heaven defend your good souls that you think
+I will your serious and great business scant
+For she is with me. No, when light-winged toys
+Of feathered Cupid seel with wanton dullness
+My speculative and officed instruments,
+That my disports corrupt and taint my business,
+Let housewives make a skillet of my helm,
+And all indign and base adversities
+Make head against my estimation.
+
+**DUKE**
+Be it as you shall privately determine,
+Either for her stay or going. Th' affair cries haste,
+And speed must answer it.
+
+**FIRST** **SENATOR**
+You must away tonight.
+
+**@O|** With all my
+heart.
+
+**DUKE**
+At nine i' th' morning here we'll meet again.
+@O|, leave some officer behind
+And he shall our commission bring to you,
+With such things else of quality and respect
+As doth import you.
+
+**@O|** So please your Grace, my
+ancient.
+A man he is of honesty and trust.
+To his conveyance I assign my wife,
+With what else needful your good Grace shall think
+To be sent after me.
+
+**DUKE** Let it be so.
+Good night to everyone. \lbracket|To @B|.\rbracket| And, noble
+signior,
+If virtue no delighted beauty lack,
+Your son-in-law is far more fair than black.
+
+**FIRST** **SENATOR**
+Adieu, brave Moor, use @D| well.
+
+**@B|**
+Look to her, Moor, if thou hast eyes to see.
+She has deceived her father, and may thee. \lbracket|He exits.\rbracket|
+
+**@O|**
+My life upon her faith!
+\lbracket|The Duke, the Senators, @C|, and Officers exit.\rbracket|
+Honest @I|,
+My @D| must I leave to thee.
+I prithee let thy wife attend on her,
+And bring them after in the best advantage.--
+Come, @D|, I have but an hour
+Of love, of worldly matters, and direction
+To spend with thee. We must obey the time.
+\lbracket|@O| and @D| exit.\rbracket|
+
+**@R|** @I|--
+
+**@I|** What sayst thou, noble heart?
+
+**@R|** What will I do, think'st thou?
+
+**@I|** Why, go to bed and sleep.
+
+**@R|** I will incontinently drown myself.
+
+**@I|** If thou dost, I shall never love thee after. Why,
+thou silly gentleman!
+
+**@R|** It is silliness to live, when to live is torment,
+and then have we a prescription to die when death is
+our physician.
+
+**@I|** O, villainous! I have looked upon the world for
+four times seven years, and since I could distinguish
+betwixt a benefit and an injury, I never found
+man that knew how to love himself. Ere I would say
+I would drown myself for the love of a guinea hen, I
+would change my humanity with a baboon.
+
+**@R|** What should I do? I confess it is my shame
+to be so fond, but it is not in my virtue to amend it.
+
+**@I|** Virtue? A fig! 'Tis in ourselves that we are thus or
+thus. Our bodies are our gardens, to the which our
+wills are gardeners. So that if we will plant nettles
+or sow lettuce, set hyssop and weed up thyme,
+supply it with one gender of herbs or distract it
+with many, either to have it sterile with idleness or
+manured with industry, why the power and corrigible
+authority of this lies in our wills. If the balance
+of our lives had not one scale of reason to poise
+another of sensuality, the blood and baseness of our
+natures would conduct us to most prepost'rous
+conclusions. But we have reason to cool our raging
+motions, our carnal stings, our unbitted lusts--
+whereof I take this that you call love to be a sect, or
+scion.
+
+**@R|** It cannot be.
+
+**@I|** It is merely a lust of the blood and a permission
+of the will. Come, be a man! Drown thyself? Drown
+cats and blind puppies. I have professed me thy
+friend, and I confess me knit to thy deserving
+with cables of perdurable toughness. I could never
+better stead thee than now. Put money in thy purse.
+Follow thou the wars\semicolon| defeat thy favor with an
+usurped beard. I say, put money in thy purse. It
+cannot be that @D| should long continue
+her love to the Moor--put money in thy purse--
+nor he his to her. It was a violent commencement in
+her, and thou shalt see an answerable sequestration
+--put but money in thy purse. These Moors are
+changeable in their wills. Fill thy purse with money.
+The food that to him now is as luscious as locusts
+shall be to him shortly as bitter as coloquintida.
+She must change for youth. When she is sated
+with his body she will find the error of her choice.
+Therefore, put money in thy purse. If thou wilt
+needs damn thyself, do it a more delicate way than
+drowning. Make all the money thou canst. If sanctimony
+and a frail vow betwixt an erring barbarian
+and a supersubtle Venetian be not too hard for my
+wits and all the tribe of hell, thou shalt enjoy her.
+Therefore make money. A pox of drowning thyself!
+It is clean out of the way. Seek thou rather to be
+hanged in compassing thy joy than to be drowned
+and go without her.
+
+**@R|** Wilt thou be fast to my hopes if I depend on
+the issue?
+
+**@I|** Thou art sure of me. Go, make money. I have
+told thee often, and I retell thee again and again, I
+hate the Moor. My cause is hearted\semicolon| thine hath no
+less reason. Let us be conjunctive in our revenge
+against him. If thou canst cuckold him, thou dost
+thyself a pleasure, me a sport. There are many
+events in the womb of time which will be delivered.
+Traverse, go, provide thy money. We will have more
+of this tomorrow. Adieu.
+
+**@R|** Where shall we meet i' th' morning?
+
+**@I|** At my lodging.
+
+**@R|** I'll be with thee betimes.
+
+**@I|** Go to, farewell. Do you hear, @R|?
+
+**@R|** What say you?
+
+**@I|** No more of drowning, do you hear?
+
+**@R|** I am changed.
+
+**@I|** Go to, farewell. Put money enough in your
+purse.
+
+**@R|** I'll sell all my land. \lbracket|He exits.\rbracket|
+
+**@I|**
+Thus do I ever make my fool my purse.
+For I mine own gained knowledge should profane
+If I would time expend with such a snipe
+But for my sport and profit. I hate the Moor,
+And it is thought abroad that 'twixt my sheets
+'Has done my office. I know not if 't be true,
+But I, for mere suspicion in that kind,
+Will do as if for surety. He holds me well.
+The better shall my purpose work on him.
+@C|'s a proper man. Let me see now:
+To get his place and to plume up my will
+In double knavery--How? how?--Let's see.
+After some time, to abuse @O|'s ear
+That he is too familiar with his wife.
+He hath a person and a smooth dispose
+To be suspected, framed to make women false.
+The Moor is of a free and open nature
+That thinks men honest that but seem to be so,
+And will as tenderly be led by th' nose
+As asses are.
+I have 't. It is engendered. Hell and night
+Must bring this monstrous birth to the world's light.
+\lbracket|He exits.\rbracket|
+
+\h1[Act 2]
+
+\h2[Scene 1]
+
+\lbracket|Enter @M| and two Gentlemen.\rbracket|
+
+
+**@M|**
+What from the cape can you discern at sea?
+
+**FIRST** **GENTLEMAN**
+Nothing at all. It is a high-wrought flood.
+I cannot 'twixt the heaven and the main
+Descry a sail.
+
+**@M|**
+Methinks the wind hath spoke aloud at land.
+A fuller blast ne'er shook our battlements.
+If it hath ruffianed so upon the sea,
+What ribs of oak, when mountains melt on them,
+Can hold the mortise? What shall we hear of this?
+
+**SECOND** **GENTLEMAN**
+A segregation of the Turkish fleet.
+For do but stand upon the foaming shore,
+The chidden billow seems to pelt the clouds,
+The wind-shaked surge, with high and monstrous
+mane,
+Seems to cast water on the burning Bear
+And quench the guards of th' ever-fixed pole.
+I never did like molestation view
+On the enchafed flood.
+
+**@M|** If that the Turkish fleet
+Be not ensheltered and embayed, they are drowned.
+It is impossible to bear it out.
+
+\lbracket|Enter a third Gentleman.\rbracket|
+
+
+**THIRD** **GENTLEMAN** News, lads! Our wars are done.
+The desperate tempest hath so banged the Turks
+That their designment halts. A noble ship of Venice
+Hath seen a grievous wrack and sufferance
+On most part of their fleet.
+
+**@M|**
+How? Is this true?
+
+**THIRD** **GENTLEMAN** The ship is here put in,
+A Veronesa. Michael @C|,
+Lieutenant to the warlike Moor @O|,
+Is come on shore\semicolon| the Moor himself at sea,
+And is in full commission here for Cyprus.
+
+**@M|**
+I am glad on 't. 'Tis a worthy governor.
+
+**THIRD** **GENTLEMAN**
+But this same @C|, though he speak of comfort
+Touching the Turkish loss, yet he looks sadly
+And prays the Moor be safe, for they were parted
+With foul and violent tempest.
+
+**@M|** Pray heaven he be\semicolon|
+For I have served him, and the man commands
+Like a full soldier. Let's to the seaside, ho!
+As well to see the vessel that's come in
+As to throw out our eyes for brave @O|,
+Even till we make the main and th' aerial blue
+An indistinct regard.
+
+**THIRD** **GENTLEMAN** Come, let's do so\semicolon|
+For every minute is expectancy
+Of more arrivance.
+
+\lbracket|Enter @C|.\rbracket|
+
+
+**@C|**
+Thanks, you the valiant of this warlike isle,
+That so approve the Moor! O, let the heavens
+Give him defense against the elements,
+For I have lost him on a dangerous sea.
+
+**@M|** Is he well shipped?
+
+**@C|**
+His bark is stoutly timbered, and his pilot
+Of very expert and approved allowance\semicolon|
+Therefore my hopes, not surfeited to death,
+Stand in bold cure.
+\lbracket|Voices cry within. "A sail, a sail, a sail!"\rbracket|
+
+\lbracket|Enter a Messenger.\rbracket|
+
+
+**@C|** What noise?
+
+**MESSENGER**
+The town is empty\semicolon| on the brow o' th' sea
+Stand ranks of people, and they cry "A sail!"
+
+**@C|**
+My hopes do shape him for the Governor.
+\lbracket|A shot.\rbracket|
+
+**SECOND** **GENTLEMAN**
+They do discharge their shot of courtesy.
+Our friends, at least.
+
+**@C|** I pray you, sir, go forth,
+And give us truth who 'tis that is arrived.
+
+**SECOND** **GENTLEMAN** I shall. \lbracket|He exits.\rbracket|
+
+**@M|**
+But, good lieutenant, is your general wived?
+
+**@C|**
+Most fortunately. He hath achieved a maid
+That paragons description and wild fame,
+One that excels the quirks of blazoning pens,
+And in th' essential vesture of creation
+Does tire the ingener.
+
+\lbracket|Enter Second Gentleman.\rbracket|
+
+How now? Who has put in?
+
+**SECOND** **GENTLEMAN**
+'Tis one @I|, ancient to the General.
+
+**@C|**
+'Has had most favorable and happy speed!
+Tempests themselves, high seas, and howling winds,
+The guttered rocks and congregated sands
+(Traitors ensteeped to clog the guiltless keel),
+As having sense of beauty, do omit
+Their mortal natures, letting go safely by
+The divine @D|.
+
+**@M|** What is she?
+
+**@C|**
+She that I spake of, our great captain's captain,
+Left in the conduct of the bold @I|,
+Whose footing here anticipates our thoughts
+A sennight's speed. Great Jove, @O| guard,
+And swell his sail with thine own powerful breath,
+That he may bless this bay with his tall ship,
+Make love's quick pants in @D|'s arms,
+Give renewed fire to our extincted spirits,
+And bring all Cyprus comfort!
+
+\lbracket|Enter @D|, @I|, @R|, and @E|.\rbracket|
+
+O, behold,
+The riches of the ship is come on shore!
+You men of Cyprus, let her have your knees.
+\lbracket|He kneels.\rbracket|
+Hail to thee, lady, and the grace of heaven,
+Before, behind thee, and on every hand
+Enwheel thee round. \lbracket|He rises.\rbracket|
+
+**@D|** I thank you, valiant @C|.
+What tidings can you tell of my lord?
+
+**@C|**
+He is not yet arrived, nor know I aught
+But that he's well and will be shortly here.
+
+**@D|**
+O, but I fear--How lost you company?
+
+**@C|**
+The great contention of sea and skies
+Parted our fellowship.
+\lbracket|Within "A sail, a sail!" A shot.\rbracket|
+But hark, a sail!
+
+**SECOND** **GENTLEMAN**
+They give their greeting to the citadel.
+This likewise is a friend.
+
+**@C|** See for the news.
+\lbracket|Second Gentleman exits.\rbracket|
+Good ancient, you are welcome. Welcome, mistress.
+\lbracket|He kisses @E|.\rbracket|
+Let it not gall your patience, good @I|,
+That I extend my manners. 'Tis my breeding
+That gives me this bold show of courtesy.
+
+**@I|**
+Sir, would she give you so much of her lips
+As of her tongue she oft bestows on me,
+You would have enough.
+
+**@D|**
+Alas, she has no speech!
+
+**@I|** In faith, too much.
+I find it still when I have list to sleep.
+Marry, before your Ladyship, I grant,
+She puts her tongue a little in her heart
+And chides with thinking.
+
+**@E|** You have little cause to say so.
+
+**@I|** Come on, come on! You are pictures out of door,
+bells in your parlors, wildcats in your kitchens,
+saints in your injuries, devils being offended, players
+in your huswifery, and huswives in your beds.
+
+**@D|** Oh, fie upon thee, slanderer.
+
+**@I|**
+Nay, it is true, or else I am a Turk.
+You rise to play, and go to bed to work.
+
+**@E|**
+You shall not write my praise.
+
+**@I|** No, let me not.
+
+**@D|**
+What wouldst write of me if thou shouldst praise
+me?
+
+**@I|**
+O, gentle lady, do not put me to 't,
+For I am nothing if not critical.
+
+**@D|**
+Come on, assay.--There's one gone to the harbor?
+
+**@I|** Ay, madam.
+
+**@D|**, \lbracket|aside\rbracket|
+I am not merry, but I do beguile
+The thing I am by seeming otherwise.--
+Come, how wouldst thou praise me?
+
+**@I|** I am about it, but indeed my invention comes
+from my pate as birdlime does from frieze: it
+plucks out brains and all. But my muse labors, and
+thus she is delivered:
+ If she be fair and wise, fairness and wit,
+ The one's for use, the other useth it.
+
+**@D|**
+Well praised! How if she be black and witty?
+
+**@I|**
+ If she be black, and thereto have a wit,
+ She'll find a white that shall her blackness hit.
+
+**@D|**
+Worse and worse.
+
+**@E|** How if fair and foolish?
+
+**@I|**
+ She never yet was foolish that was fair,
+ For even her folly helped her to an heir.
+
+**@D|** These are old fond paradoxes to make
+fools laugh i' th' alehouse. What miserable praise
+hast thou for her that's foul and foolish?
+
+**@I|**
+ There's none so foul and foolish thereunto,
+ But does foul pranks which fair and wise ones do.
+
+**@D|** O heavy ignorance! Thou praisest the
+worst best. But what praise couldst thou bestow on
+a deserving woman indeed, one that in the authority
+of her merit did justly put on the vouch of very
+malice itself?
+
+**@I|**
+ She that was ever fair and never proud,
+ Had tongue at will and yet was never loud,
+ Never lacked gold and yet went never gay,
+ Fled from her wish, and yet said "Now I may,"
+ She that being angered, her revenge being nigh,
+ Bade her wrong stay and her displeasure fly,
+ She that in wisdom never was so frail
+ To change the cod's head for the salmon's tail,
+ She that could think and ne'er disclose her mind,
+ See suitors following and not look behind,
+ She was a wight, if ever such wight were--
+
+**@D|** To do what?
+
+**@I|**
+ To suckle fools and chronicle small beer.
+
+**@D|** O, most lame and impotent conclusion!
+--Do not learn of him, @E|, though he be thy
+husband.--How say you, @C|? Is he not a most
+profane and liberal counselor?
+
+**@C|** He speaks home, madam. You may relish him
+more in the soldier than in the scholar.
+\lbracket|@C| takes @D|'s hand.\rbracket|
+
+**@I|**, \lbracket|aside\rbracket| He takes her by the palm. Ay, well said,
+whisper. With as little a web as this will I ensnare as
+great a fly as @C|. Ay, smile upon her, do. I will
+gyve thee in thine own courtship. You say true, 'tis
+so indeed. If such tricks as these strip you out of
+your lieutenantry, it had been better you had not
+kissed your three fingers so oft, which now again
+you are most apt to play the sir in. Very good\semicolon| well
+kissed\semicolon| an excellent courtesy! 'Tis so, indeed. Yet
+again your fingers to your lips? Would they were
+clyster pipes for your sake! \lbracket|Trumpets within.\rbracket|
+The Moor. I know his trumpet.
+
+**@C|** 'Tis truly so.
+
+**@D|** Let's meet him and receive him.
+
+**@C|** Lo, where he comes!
+
+\lbracket|Enter @O| and Attendants.\rbracket|
+
+
+**@O|**
+O, my fair warrior!
+
+**@D|** My dear @O|!
+
+**@O|**
+It gives me wonder great as my content
+To see you here before me. O my soul's joy!
+If after every tempest come such calms,
+May the winds blow till they have wakened death,
+And let the laboring bark climb hills of seas
+Olympus high, and duck again as low
+As hell's from heaven! If it were now to die,
+'Twere now to be most happy, for I fear
+My soul hath her content so absolute
+That not another comfort like to this
+Succeeds in unknown fate.
+
+**@D|** The heavens forbid
+But that our loves and comforts should increase
+Even as our days do grow!
+
+**@O|** Amen to that, sweet powers!
+I cannot speak enough of this content.
+It stops me here\semicolon| it is too much of joy. \lbracket|They kiss.\rbracket|
+And this, and this, the greatest discords be
+That e'er our hearts shall make!
+
+**@I|**, \lbracket|aside\rbracket| O, you are well tuned now,
+But I'll set down the pegs that make this music,
+As honest as I am.
+
+**@O|** Come. Let us to the castle.--
+News, friends! Our wars are done. The Turks are
+drowned.
+How does my old acquaintance of this isle?--
+Honey, you shall be well desired in Cyprus.
+I have found great love amongst them. O, my sweet,
+I prattle out of fashion, and I dote
+In mine own comforts.--I prithee, good @I|,
+Go to the bay and disembark my coffers.
+Bring thou the master to the citadel.
+He is a good one, and his worthiness
+Does challenge much respect.--Come, @D|.
+Once more, well met at Cyprus.
+\lbracket|All but @I| and @R| exit.\rbracket|
+
+**@I|**, \lbracket|to a departing Attendant\rbracket| Do thou meet me presently
+at the harbor. \lbracket|To @R|.\rbracket| Come hither. If
+thou be'st valiant--as they say base men being in
+love have then a nobility in their natures more than
+is native to them--list me. The Lieutenant tonight
+watches on the court of guard. First, I must tell thee
+this: @D| is directly in love with him.
+
+**@R|** With him? Why, 'tis not possible.
+
+**@I|** Lay thy finger thus, and let thy soul be instructed.
+Mark me with what violence she first loved the
+Moor but for bragging and telling her fantastical
+lies. And will she love him still for prating? Let not
+thy discreet heart think it. Her eye must be fed. And
+what delight shall she have to look on the devil?
+When the blood is made dull with the act of sport,
+there should be, again to inflame it and to give
+satiety a fresh appetite, loveliness in favor, sympathy
+in years, manners, and beauties, all which the Moor
+is defective in. Now, for want of these required
+conveniences, her delicate tenderness will find itself
+abused, begin to heave the gorge, disrelish and
+abhor the Moor. Very nature will instruct her in it
+and compel her to some second choice. Now, sir,
+this granted--as it is a most pregnant and unforced
+position--who stands so eminent in the degree of
+this fortune as @C| does? A knave very voluble, no
+further conscionable than in putting on the mere
+form of civil and humane seeming for the better
+compassing of his salt and most hidden loose
+affection. Why, none, why, none! A slipper and
+subtle knave, a finder-out of occasions, that has an
+eye can stamp and counterfeit advantages, though
+true advantage never present itself\semicolon| a devilish knave!
+Besides, the knave is handsome, young, and hath all
+those requisites in him that folly and green minds
+look after. A pestilent complete knave, and the
+woman hath found him already.
+
+**@R|** I cannot believe that in her. She's full of
+most blessed condition.
+
+**@I|** Blessed fig's end! The wine she drinks is made of
+grapes. If she had been blessed, she would never
+have loved the Moor. Blessed pudding! Didst thou
+not see her paddle with the palm of his hand? Didst
+not mark that?
+
+**@R|** Yes, that I did. But that was but courtesy.
+
+**@I|** Lechery, by this hand! An index and obscure
+prologue to the history of lust and foul thoughts.
+They met so near with their lips that their breaths
+embraced together. Villainous thoughts, @R|!
+When these mutualities so marshal the way, hard
+at hand comes the master and main exercise, th'
+incorporate conclusion. Pish! But, sir, be you ruled
+by me. I have brought you from Venice. Watch you
+tonight. For the command, I'll lay 't upon you.
+@C| knows you not. I'll not be far from you. Do
+you find some occasion to anger @C|, either by
+speaking too loud, or tainting his discipline, or from
+what other course you please, which the time shall
+more favorably minister.
+
+**@R|** Well.
+
+**@I|** Sir, he's rash and very sudden in choler, and
+haply may strike at you. Provoke him that he may,
+for even out of that will I cause these of Cyprus to
+mutiny, whose qualification shall come into no
+true taste again but by the displanting of @C|. So
+shall you have a shorter journey to your desires by
+the means I shall then have to prefer them, and the
+impediment most profitably removed, without the
+which there were no expectation of our prosperity.
+
+**@R|** I will do this, if you can bring it to any
+opportunity.
+
+**@I|** I warrant thee. Meet me by and by at the citadel. I
+must fetch his necessaries ashore. Farewell.
+
+**@R|** Adieu. \lbracket|He exits.\rbracket|
+
+**@I|**
+That @C| loves her, I do well believe 't.
+That she loves him, 'tis apt and of great credit.
+The Moor, howbeit that I endure him not,
+Is of a constant, loving, noble nature,
+And I dare think he'll prove to @D|
+A most dear husband. Now, I do love her too,
+Not out of absolute lust (though peradventure
+I stand accountant for as great a sin)
+But partly led to diet my revenge
+For that I do suspect the lusty Moor
+Hath leaped into my seat--the thought whereof
+Doth, like a poisonous mineral, gnaw my inwards,
+And nothing can or shall content my soul
+Till I am evened with him, wife for wife,
+Or, failing so, yet that I put the Moor
+At least into a jealousy so strong
+That judgment cannot cure. Which thing to do,
+If this poor trash of Venice, whom I trace
+For his quick hunting, stand the putting on,
+I'll have our Michael @C| on the hip,
+Abuse him to the Moor in the rank garb
+(For I fear @C| with my nightcap too),
+Make the Moor thank me, love me, and reward me
+For making him egregiously an ass
+And practicing upon his peace and quiet
+Even to madness. 'Tis here, but yet confused.
+Knavery's plain face is never seen till used.
+\lbracket|He exits.\rbracket|
+
+\h2[Scene 2]
+
+\lbracket|Enter @O|'s Herald with a proclamation.\rbracket|
+
+
+**HERALD** It is @O|'s pleasure, our noble and valiant
+general, that upon certain tidings now arrived,
+importing the mere perdition of the Turkish fleet,
+every man put himself into triumph: some to
+dance, some to make bonfires, each man to what
+sport and revels his addition leads him. For besides
+these beneficial news, it is the celebration of his
+nuptial. So much was his pleasure should be proclaimed
+All offices are open, and there is full
+liberty of feasting from this present hour of five till
+the bell have told eleven. Heaven bless the isle of
+Cyprus and our noble general, @O|!
+\lbracket|He exits.\rbracket|
+
+\h2[Scene 3]
+
+\lbracket|Enter @O|, @D|, @C|, and Attendants.\rbracket|
+
+
+**@O|**
+Good Michael, look you to the guard tonight.
+Let's teach ourselves that honorable stop
+Not to outsport discretion.
+
+**@C|**
+@I| hath direction what to do,
+But notwithstanding, with my personal eye
+Will I look to 't.
+
+**@O|** @I| is most honest.
+Michael, goodnight. Tomorrow with your earliest
+Let me have speech with you. \lbracket|To @D|.\rbracket| Come,
+my dear love,
+The purchase made, the fruits are to ensue\semicolon|
+That profit's yet to come 'tween me and you.--
+Goodnight.
+\lbracket|@O| and @D| exit, with Attendants.\rbracket|
+
+\lbracket|Enter @I|.\rbracket|
+
+
+**@C|**
+Welcome, @I|. We must to the watch.
+
+**@I|** Not this hour, lieutenant. 'Tis not yet ten o' th'
+clock. Our general cast us thus early for the love of
+his @D|--who let us not therefore blame\semicolon|
+he hath not yet made wanton the night with her, and
+she is sport for Jove.
+
+**@C|** She's a most exquisite lady.
+
+**@I|** And, I'll warrant her, full of game.
+
+**@C|** Indeed, she's a most fresh and delicate
+creature.
+
+**@I|** What an eye she has! Methinks it sounds a parley
+to provocation.
+
+**@C|** An inviting eye, and yet methinks right
+modest.
+
+**@I|** And when she speaks, is it not an alarum to love?
+
+**@C|** She is indeed perfection.
+
+**@I|** Well, happiness to their sheets! Come, lieutenant,
+I have a stoup of wine\semicolon| and here without are a
+brace of Cyprus gallants that would fain have a
+measure to the health of black @O|.
+
+**@C|** Not tonight, good @I|. I have very poor and
+unhappy brains for drinking. I could well wish
+courtesy would invent some other custom of
+entertainment.
+
+**@I|** O, they are our friends! But one cup\semicolon| I'll drink
+for you.
+
+**@C|** I have drunk but one cup tonight, and that was
+craftily qualified too, and behold what innovation it
+makes here. I am unfortunate in the infirmity and
+dare not task my weakness with any more.
+
+**@I|** What, man! 'Tis a night of revels. The gallants
+desire it.
+
+**@C|** Where are they?
+
+**@I|** Here at the door. I pray you, call them in.
+
+**@C|** I'll do 't, but it dislikes me. \lbracket|He exits.\rbracket|
+
+**@I|**
+If I can fasten but one cup upon him
+With that which he hath drunk tonight already,
+He'll be as full of quarrel and offense
+As my young mistress' dog. Now my sick fool
+@R|,
+Whom love hath turned almost the wrong side out,
+To @D| hath tonight caroused
+Potations pottle-deep\semicolon| and he's to watch.
+Three else of Cyprus, noble swelling spirits
+That hold their honors in a wary distance,
+The very elements of this warlike isle,
+Have I tonight flustered with flowing cups\semicolon|
+And they watch too. Now, 'mongst this flock of
+drunkards
+Am I to put our @C| in some action
+That may offend the isle. But here they come.
+If consequence do but approve my dream,
+My boat sails freely both with wind and stream.
+
+\lbracket|Enter @C|, @M|, and Gentlemen, followed by
+Servants with wine.\rbracket|
+
+
+**@C|** 'Fore God, they have given me a rouse
+already.
+
+**@M|** Good faith, a little one\semicolon| not past a pint, as I
+am a soldier.
+
+**@I|** Some wine, ho!
+\lbracket|Sings.\rbracket| And let me the cannikin clink, clink,
+ And let me the cannikin clink.
+ A soldier's a man,
+ O, man's life's but a span,
+ Why, then, let a soldier drink.
+Some wine, boys!
+
+**@C|** 'Fore God, an excellent song.
+
+**@I|** I learned it in England, where indeed they are
+most potent in potting. Your Dane, your German,
+and your swag-bellied Hollander--drink, ho!--are
+nothing to your English.
+
+**@C|** Is your Englishman so exquisite in his
+drinking?
+
+**@I|** Why, he drinks you, with facility, your Dane
+dead drunk. He sweats not to overthrow your Almain.
+He gives your Hollander a vomit ere the next
+pottle can be filled.
+
+**@C|** To the health of our general!
+
+**@M|** I am for it, lieutenant, and I'll do you
+justice.
+
+**@I|** O sweet England!
+\lbracket|Sings.\rbracket| King Stephen was and-a worthy peer,
+ His breeches cost him but a crown\semicolon|
+ He held them sixpence all too dear\semicolon|
+ With that he called the tailor lown.
+ He was a wight of high renown,
+ And thou art but of low degree\semicolon|
+ 'Tis pride that pulls the country down,
+ Then take thy auld cloak about thee.
+Some wine, ho!
+
+**@C|** 'Fore God, this is a more exquisite song than
+the other!
+
+**@I|** Will you hear 't again?
+
+**@C|** No, for I hold him to be unworthy of his place
+that does those things. Well, God's above all\semicolon| and
+there be souls must be saved, and there be souls
+must not be saved.
+
+**@I|** It's true, good lieutenant.
+
+**@C|** For mine own part--no offense to the General,
+nor any man of quality--I hope to be saved.
+
+**@I|** And so do I too, lieutenant.
+
+**@C|** Ay, but, by your leave, not before me. The
+Lieutenant is to be saved before the Ancient. Let's
+have no more of this. Let's to our affairs. God
+forgive us our sins! Gentlemen, let's look to our
+business. Do not think, gentlemen, I am drunk. This
+is my ancient, this is my right hand, and this is my
+left. I am not drunk now. I can stand well enough,
+and I speak well enough.
+
+**GENTLEMEN** Excellent well.
+
+**@C|** Why, very well then. You must not think then
+that I am drunk. \lbracket|He exits.\rbracket|
+
+**@M|**
+To th' platform, masters. Come, let's set the watch.
+\lbracket|Gentlemen exit.\rbracket|
+
+**@I|**, \lbracket|to @M|\rbracket|
+You see this fellow that is gone before?
+He's a soldier fit to stand by Caesar
+And give direction\semicolon| and do but see his vice.
+'Tis to his virtue a just equinox,
+The one as long as th' other. 'Tis pity of him.
+I fear the trust @O| puts him in,
+On some odd time of his infirmity,
+Will shake this island.
+
+**@M|** But is he often thus?
+
+**@I|**
+'Tis evermore the prologue to his sleep.
+He'll watch the horologe a double set
+If drink rock not his cradle.
+
+**@M|** It were well
+The General were put in mind of it.
+Perhaps he sees it not, or his good nature
+Prizes the virtue that appears in @C|
+And looks not on his evils. Is not this true?
+
+\lbracket|Enter @R|.\rbracket|
+
+
+**@I|**, \lbracket|aside to @R|\rbracket| How now, @R|?
+I pray you, after the Lieutenant, go.
+\lbracket|@R| exits.\rbracket|
+
+**@M|**
+And 'tis great pity that the noble Moor
+Should hazard such a place as his own second
+With one of an engraffed infirmity.
+It were an honest action to say so
+To the Moor.
+
+**@I|** Not I, for this fair island.
+I do love @C| well and would do much
+To cure him of this evil-- \lbracket|"Help, help!" within.\rbracket|
+But hark! What noise?
+
+\lbracket|Enter @C|, pursuing @R|.\rbracket|
+
+
+**@C|** Zounds, you rogue, you rascal!
+
+**@M|** What's the matter, lieutenant?
+
+**@C|** A knave teach me my duty? I'll beat the knave
+into a twiggen bottle.
+
+**@R|** Beat me?
+
+**@C|** Dost thou prate, rogue? \lbracket|He hits @R|.\rbracket|
+
+**@M|** Nay, good lieutenant. I pray you, sir, hold
+your hand.
+
+**@C|** Let me go, sir, or I'll knock you o'er the
+mazard.
+
+**@M|** Come, come, you're drunk.
+
+**@C|** Drunk?
+\lbracket|They fight.\rbracket|
+
+**@I|**, \lbracket|aside to @R|\rbracket|
+Away, I say! Go out and cry a mutiny.
+\lbracket|@R| exits.\rbracket|
+Nay, good lieutenant.--God's will, gentlemen!--
+Help, ho! Lieutenant--sir--@M|--sir--
+Help, masters!--Here's a goodly watch indeed!
+\lbracket|A bell is rung.\rbracket|
+Who's that which rings the bell? Diablo, ho!
+The town will rise. God's will, lieutenant, hold!
+You will be shamed forever.
+
+\lbracket|Enter @O| and Attendants.\rbracket|
+
+
+**@O|**
+What is the matter here?
+
+**@M|** Zounds, I bleed
+still.
+I am hurt to th' death. He dies! \lbracket|He attacks @C|.\rbracket|
+
+**@O|** Hold, for your lives!
+
+**@I|**
+Hold, ho! Lieutenant--sir--@M|--
+gentlemen--
+Have you forgot all sense of place and duty?
+Hold! The General speaks to you. Hold, for shame!
+
+**@O|**
+Why, how now, ho! From whence ariseth this?
+Are we turned Turks, and to ourselves do that
+Which heaven hath forbid the Ottomites?
+For Christian shame, put by this barbarous brawl!
+He that stirs next to carve for his own rage
+Holds his soul light\semicolon| he dies upon his motion.
+Silence that dreadful bell. It frights the isle
+From her propriety. What is the matter, masters?
+Honest @I|, that looks dead with grieving,
+Speak. Who began this? On thy love, I charge thee.
+
+**@I|**
+I do not know. Friends all but now, even now,
+In quarter and in terms like bride and groom
+Divesting them for bed\semicolon| and then but now,
+As if some planet had unwitted men,
+Swords out, and tilting one at other's breast,
+In opposition bloody. I cannot speak
+Any beginning to this peevish odds,
+And would in action glorious I had lost
+Those legs that brought me to a part of it!
+
+**@O|**
+How comes it, Michael, you are thus forgot?
+
+**@C|**
+I pray you pardon me\semicolon| I cannot speak.
+
+**@O|**
+Worthy @M|, you were wont be civil.
+The gravity and stillness of your youth
+The world hath noted. And your name is great
+In mouths of wisest censure. What's the matter
+That you unlace your reputation thus,
+And spend your rich opinion for the name
+Of a night-brawler? Give me answer to it.
+
+**@M|**
+Worthy @O|, I am hurt to danger.
+Your officer @I| can inform you,
+While I spare speech, which something now offends
+me,
+Of all that I do know\semicolon| nor know I aught
+By me that's said or done amiss this night,
+Unless self-charity be sometimes a vice,
+And to defend ourselves it be a sin
+When violence assails us.
+
+**@O|** Now, by heaven,
+My blood begins my safer guides to rule,
+And passion, having my best judgment collied,
+Assays to lead the way. Zounds, if I stir,
+Or do but lift this arm, the best of you
+Shall sink in my rebuke. Give me to know
+How this foul rout began, who set it on\semicolon|
+And he that is approved in this offense,
+Though he had twinned with me, both at a birth,
+Shall lose me. What, in a town of war
+Yet wild, the people's hearts brimful of fear,
+To manage private and domestic quarrel,
+In night, and on the court and guard of safety?
+'Tis monstrous. @I|, who began 't?
+
+**@M|**
+If partially affined, or leagued in office,
+Thou dost deliver more or less than truth,
+Thou art no soldier.
+
+**@I|** Touch me not so near.
+I had rather have this tongue cut from my mouth
+Than it should do offense to Michael @C|.
+Yet I persuade myself, to speak the truth
+Shall nothing wrong him. Thus it is, general:
+@M| and myself being in speech,
+There comes a fellow crying out for help,
+And @C| following him with determined sword
+To execute upon him. Sir, this gentleman
+\lbracket|Pointing to @M|.\rbracket|
+Steps in to @C| and entreats his pause.
+Myself the crying fellow did pursue,
+Lest by his clamor--as it so fell out--
+The town might fall in fright. He, swift of foot,
+Outran my purpose, and I returned the rather
+For that I heard the clink and fall of swords
+And @C| high in oath, which till tonight
+I ne'er might say before. When I came back--
+For this was brief--I found them close together
+At blow and thrust, even as again they were
+When you yourself did part them.
+More of this matter cannot I report.
+But men are men\semicolon| the best sometimes forget.
+Though @C| did some little wrong to him,
+As men in rage strike those that wish them best,
+Yet surely @C|, I believe, received
+From him that fled some strange indignity
+Which patience could not pass.
+
+**@O|** I know, @I|,
+Thy honesty and love doth mince this matter,
+Making it light to @C|.--@C|, I love thee,
+But nevermore be officer of mine.
+
+\lbracket|Enter @D| attended.\rbracket|
+
+Look if my gentle love be not raised up!
+I'll make thee an example.
+
+**@D|**
+What is the matter, dear?
+
+**@O|** All's well now,
+sweeting.
+Come away to bed. \lbracket|To @M|.\rbracket| Sir, for your hurts,
+Myself will be your surgeon.--Lead him off.
+\lbracket|@M| is led off.\rbracket|
+@I|, look with care about the town
+And silence those whom this vile brawl
+distracted.--
+Come, @D|. 'Tis the soldier's life
+To have their balmy slumbers waked with strife.
+\lbracket|All but @I| and @C| exit.\rbracket|
+
+**@I|** What, are you hurt, lieutenant?
+
+**@C|** Ay, past all surgery.
+
+**@I|** Marry, God forbid!
+
+**@C|** Reputation, reputation, reputation! O, I have
+lost my reputation! I have lost the immortal part of
+myself, and what remains is bestial. My reputation,
+@I|, my reputation!
+
+**@I|** As I am an honest man, I thought you had
+received some bodily wound. There is more sense
+in that than in reputation. Reputation is an idle and
+most false imposition, oft got without merit and lost
+without deserving. You have lost no reputation at
+all, unless you repute yourself such a loser. What,
+man, there are ways to recover the General again!
+You are but now cast in his mood--a punishment
+more in policy than in malice, even so as one would
+beat his offenseless dog to affright an imperious
+lion. Sue to him again and he's yours.
+
+**@C|** I will rather sue to be despised than to deceive
+so good a commander with so slight, so drunken,
+and so indiscreet an officer. Drunk? And speak
+parrot? And squabble? Swagger? Swear? And discourse
+fustian with one's own shadow? O thou
+invisible spirit of wine, if thou hast no name to be
+known by, let us call thee devil!
+
+**@I|** What was he that you followed with your sword?
+What had he done to you?
+
+**@C|** I know not.
+
+**@I|** Is 't possible?
+
+**@C|** I remember a mass of things, but nothing
+distinctly\semicolon| a quarrel, but nothing wherefore. O
+God, that men should put an enemy in their
+mouths to steal away their brains! That we should
+with joy, pleasance, revel, and applause transform
+ourselves into beasts!
+
+**@I|** Why, but you are now well enough. How came
+you thus recovered?
+
+**@C|** It hath pleased the devil drunkenness to give
+place to the devil wrath. One unperfectness shows
+me another, to make me frankly despise myself.
+
+**@I|** Come, you are too severe a moraler. As the time,
+the place, and the condition of this country stands,
+I could heartily wish this had not so befallen. But
+since it is as it is, mend it for your own good.
+
+**@C|** I will ask him for my place again\semicolon| he shall tell
+me I am a drunkard! Had I as many mouths as
+Hydra, such an answer would stop them all. To be
+now a sensible man, by and by a fool, and presently
+a beast! O, strange! Every inordinate cup is unblessed,
+and the ingredient is a devil.
+
+**@I|** Come, come, good wine is a good familiar creature,
+if it be well used. Exclaim no more against it.
+And, good lieutenant, I think you think I love you.
+
+**@C|** I have well approved it, sir.--I drunk!
+
+**@I|** You or any man living may be drunk at a time,
+man. I'll tell you what you shall do. Our general's
+wife is now the general: I may say so in this
+respect, for that he hath devoted and given up
+himself to the contemplation, mark, and denotement
+of her parts and graces. Confess yourself
+freely to her. Importune her help to put you in your
+place again. She is of so free, so kind, so apt, so
+blessed a disposition she holds it a vice in her
+goodness not to do more than she is requested. This
+broken joint between you and her husband entreat
+her to splinter, and, my fortunes against any lay
+worth naming, this crack of your love shall grow
+stronger than it was before.
+
+**@C|** You advise me well.
+
+**@I|** I protest, in the sincerity of love and honest
+kindness.
+
+**@C|** I think it freely\semicolon| and betimes in the morning I
+will beseech the virtuous @D| to undertake
+for me. I am desperate of my fortunes if they check
+me here.
+
+**@I|** You are in the right. Good night, lieutenant. I
+must to the watch.
+
+**@C|** Good night, honest @I|. \lbracket|@C| exits.\rbracket|
+
+**@I|**
+And what's he, then, that says I play the villain,
+When this advice is free I give and honest,
+Probal to thinking, and indeed the course
+To win the Moor again? For 'tis most easy
+Th' inclining @D| to subdue
+In any honest suit. She's framed as fruitful
+As the free elements. And then for her
+To win the Moor--were 't to renounce his baptism,
+All seals and symbols of redeemed sin--
+His soul is so enfettered to her love
+That she may make, unmake, do what she list,
+Even as her appetite shall play the god
+With his weak function. How am I then a villain
+To counsel @C| to this parallel course
+Directly to his good? Divinity of hell!
+When devils will the blackest sins put on,
+They do suggest at first with heavenly shows,
+As I do now. For whiles this honest fool
+Plies @D| to repair his fortune,
+And she for him pleads strongly to the Moor,
+I'll pour this pestilence into his ear:
+That she repeals him for her body's lust\semicolon|
+And by how much she strives to do him good,
+She shall undo her credit with the Moor.
+So will I turn her virtue into pitch,
+And out of her own goodness make the net
+That shall enmesh them all.
+
+\lbracket|Enter @R|.\rbracket|
+
+How now, @R|?
+
+**@R|** I do follow here in the chase, not like a
+hound that hunts, but one that fills up the cry. My
+money is almost spent, I have been tonight exceedingly
+well cudgeled, and I think the issue will be I
+shall have so much experience for my pains, and so,
+with no money at all and a little more wit, return
+again to Venice.
+
+**@I|**
+How poor are they that have not patience!
+What wound did ever heal but by degrees?
+Thou know'st we work by wit and not by witchcraft,
+And wit depends on dilatory time.
+Does 't not go well? @C| hath beaten thee,
+And thou, by that small hurt, hast cashiered @C|.
+Though other things grow fair against the sun,
+Yet fruits that blossom first will first be ripe.
+Content thyself awhile. By th' Mass, 'tis morning!
+Pleasure and action make the hours seem short.
+Retire thee\semicolon| go where thou art billeted.
+Away, I say! Thou shalt know more hereafter.
+Nay, get thee gone. \lbracket|@R| exits.\rbracket|
+Two things are to be done.
+My wife must move for @C| to her mistress.
+I'll set her on.
+Myself the while to draw the Moor apart
+And bring him jump when he may @C| find
+Soliciting his wife. Ay, that's the way.
+Dull not device by coldness and delay.
+\lbracket|He exits.\rbracket|
+
+\h1[Act 3]
+
+\h2[Scene 1]
+
+\lbracket|Enter @C| with Musicians.\rbracket|
+
+
+**@C|**
+Masters, play here (I will content your pains)
+Something that's brief\semicolon| and bid "Good morrow,
+general." \lbracket|They play.\rbracket|
+
+\lbracket|Enter the Clown.\rbracket|
+
+
+**CLOWN** Why masters, have your instruments been in
+Naples, that they speak i' th' nose thus?
+
+**MUSICIAN** How, sir, how?
+
+**CLOWN** Are these, I pray you, wind instruments?
+
+**MUSICIAN** Ay, marry, are they, sir.
+
+**CLOWN** O, thereby hangs a tail.
+
+**MUSICIAN** Whereby hangs a tale, sir?
+
+**CLOWN** Marry, sir, by many a wind instrument that I
+know. But, masters, here's money for you\semicolon| and the
+General so likes your music that he desires you, for
+love's sake, to make no more noise with it.
+
+**MUSICIAN** Well, sir, we will not.
+
+**CLOWN** If you have any music that may not be heard, to
+'t again. But, as they say, to hear music the General
+does not greatly care.
+
+**MUSICIAN** We have none such, sir.
+
+**CLOWN** Then put up your pipes in your bag, for I'll
+away. Go, vanish into air, away!
+
+\lbracket|Musicians exit.\rbracket|
+
+**@C|** Dost thou hear, mine honest friend?
+
+**CLOWN** No, I hear not your honest friend. I hear you.
+
+**@C|** Prithee, keep up thy quillets. \lbracket|Giving money.\rbracket|
+There's a poor piece of gold for thee. If the gentlewoman
+that attends the General's wife be stirring,
+tell her there's one @C| entreats her a little favor
+of speech. Wilt thou do this?
+
+**CLOWN** She is stirring, sir. If she will stir hither, I shall
+seem to notify unto her.
+
+**@C|**
+Do, good my friend. \lbracket|Clown exits.\rbracket|
+
+\lbracket|Enter @I|.\rbracket|
+
+In happy time, @I|.
+
+**@I|** You have not been abed, then?
+
+**@C|** Why, no. The day had broke
+Before we parted. I have made bold, @I|,
+To send in to your wife. My suit to her
+Is that she will to virtuous @D|
+Procure me some access.
+
+**@I|** I'll send her to you presently,
+And I'll devise a mean to draw the Moor
+Out of the way, that your converse and business
+May be more free.
+
+**@C|**
+I humbly thank you for 't. \lbracket|@I| exits.\rbracket| I never
+knew
+A Florentine more kind and honest.
+
+\lbracket|Enter @E|.\rbracket|
+
+
+**@E|**
+Good morrow, good lieutenant. I am sorry
+For your displeasure, but all will sure be well.
+The General and his wife are talking of it,
+And she speaks for you stoutly. The Moor replies
+That he you hurt is of great fame in Cyprus
+And great affinity, and that in wholesome wisdom
+He might not but refuse you. But he protests he
+loves you
+And needs no other suitor but his likings
+To take the safest occasion by the front
+To bring you in again.
+
+**@C|** Yet I beseech you,
+If you think fit, or that it may be done,
+Give me advantage of some brief discourse
+With Desdemon alone.
+
+**@E|** Pray you come in.
+I will bestow you where you shall have time
+To speak your bosom freely.
+
+**@C|** I am much bound to you.
+\lbracket|They exit.\rbracket|
+
+\h2[Scene 2]
+
+\lbracket|Enter @O|, @I|, and Gentlemen.\rbracket|
+
+
+**@O|**
+These letters give, @I|, to the pilot
+And by him do my duties to the Senate.
+\lbracket|He gives @I| some papers.\rbracket|
+That done, I will be walking on the works.
+Repair there to me.
+
+**@I|** Well, my good lord, I'll do 't.
+
+**@O|**
+This fortification, gentlemen, shall we see 't?
+
+**GENTLEMEN**
+We wait upon your Lordship.
+\lbracket|They exit.\rbracket|
+
+\h2[Scene 3]
+
+\lbracket|Enter @D|, @C|, and @E|.\rbracket|
+
+
+**@D|**
+Be thou assured, good @C|, I will do
+All my abilities in thy behalf.
+
+**@E|**
+Good madam, do. I warrant it grieves my husband
+As if the cause were his.
+
+**@D|**
+O, that's an honest fellow! Do not doubt, @C|,
+But I will have my lord and you again
+As friendly as you were.
+
+**@C|** Bounteous madam,
+Whatever shall become of Michael @C|,
+He's never anything but your true servant.
+
+**@D|**
+I know 't. I thank you. You do love my lord\semicolon|
+You have known him long\semicolon| and be you well assured
+He shall in strangeness stand no farther off
+Than in a politic distance.
+
+**@C|** Ay, but, lady,
+That policy may either last so long,
+Or feed upon such nice and waterish diet,
+Or breed itself so out of circumstance,
+That, I being absent and my place supplied,
+My general will forget my love and service.
+
+**@D|**
+Do not doubt that. Before @E| here,
+I give thee warrant of thy place. Assure thee,
+If I do vow a friendship, I'll perform it
+To the last article. My lord shall never rest:
+I'll watch him tame and talk him out of patience\semicolon|
+His bed shall seem a school, his board a shrift\semicolon|
+I'll intermingle everything he does
+With @C|'s suit. Therefore be merry, @C|,
+For thy solicitor shall rather die
+Than give thy cause away.
+
+\lbracket|Enter @O| and @I|.\rbracket|
+
+
+**@E|** Madam, here comes my lord.
+
+**@C|** Madam, I'll take my leave.
+
+**@D|** Why, stay, and hear me speak.
+
+**@C|**
+Madam, not now. I am very ill at ease,
+Unfit for mine own purposes.
+
+**@D|** Well, do your discretion. \lbracket|@C| exits.\rbracket|
+
+**@I|**
+Ha, I like not that.
+
+**@O|** What dost thou say?
+
+**@I|**
+Nothing, my lord\semicolon| or if--I know not what.
+
+**@O|**
+Was not that @C| parted from my wife?
+
+**@I|**
+@C|, my lord? No, sure, I cannot think it
+That he would steal away so guiltylike,
+Seeing your coming.
+
+**@O|** I do believe 'twas he.
+
+**@D|** How now, my lord?
+I have been talking with a suitor here,
+A man that languishes in your displeasure.
+
+**@O|** Who is 't you mean?
+
+**@D|**
+Why, your lieutenant, @C|. Good my lord,
+If I have any grace or power to move you,
+His present reconciliation take\semicolon|
+For if he be not one that truly loves you,
+That errs in ignorance and not in cunning,
+I have no judgment in an honest face.
+I prithee call him back.
+
+**@O|** Went he hence now?
+
+**@D|** Yes, faith, so humbled
+That he hath left part of his grief with me
+To suffer with him. Good love, call him back.
+
+**@O|**
+Not now, sweet Desdemon. Some other time.
+
+**@D|**
+But shall 't be shortly?
+
+**@O|** The sooner, sweet, for you.
+
+**@D|**
+Shall 't be tonight at supper?
+
+**@O|** No, not tonight.
+
+**@D|** Tomorrow dinner, then?
+
+**@O|** I shall not dine at home\semicolon|
+I meet the captains at the citadel.
+
+**@D|**
+Why then tomorrow night, or Tuesday morn,
+On Tuesday noon or night\semicolon| on Wednesday morn.
+I prithee name the time, but let it not
+Exceed three days. In faith, he's penitent\semicolon|
+And yet his trespass, in our common reason--
+Save that, they say, the wars must make example
+Out of her best--is not almost a fault
+T' incur a private check. When shall he come?
+Tell me, @O|. I wonder in my soul
+What you would ask me that I should deny,
+Or stand so mamm'ring on? What? Michael @C|,
+That came a-wooing with you, and so many a time,
+When I have spoke of you dispraisingly,
+Hath ta'en your part--to have so much to do
+To bring him in! By 'r Lady, I could do much--
+
+**@O|**
+Prithee, no more. Let him come when he will\semicolon|
+I will deny thee nothing.
+
+**@D|** Why, this is not a boon!
+'Tis as I should entreat you wear your gloves,
+Or feed on nourishing dishes, or keep you warm,
+Or sue to you to do a peculiar profit
+To your own person. Nay, when I have a suit
+Wherein I mean to touch your love indeed,
+It shall be full of poise and difficult weight,
+And fearful to be granted.
+
+**@O|** I will deny thee nothing!
+Whereon, I do beseech thee, grant me this,
+To leave me but a little to myself.
+
+**@D|**
+Shall I deny you? No. Farewell, my lord.
+
+**@O|**
+Farewell, my @D|. I'll come to thee straight.
+
+**@D|**
+@E|, come.--Be as your fancies teach you.
+Whate'er you be, I am obedient.
+\lbracket|@D| and @E| exit.\rbracket|
+
+**@O|**
+Excellent wretch! Perdition catch my soul
+But I do love thee! And when I love thee not,
+Chaos is come again.
+
+**@I|** My noble lord--
+
+**@O|**
+What dost thou say, @I|?
+
+**@I|** Did Michael @C|,
+When you wooed my lady, know of your love?
+
+**@O|**
+He did, from first to last. Why dost thou ask?
+
+**@I|**
+But for a satisfaction of my thought,
+No further harm.
+
+**@O|** Why of thy thought, @I|?
+
+**@I|**
+I did not think he had been acquainted with her.
+
+**@O|**
+O yes, and went between us very oft.
+
+**@I|** Indeed?
+
+**@O|**
+Indeed? Ay, indeed! Discern'st thou aught in that?
+Is he not honest?
+
+**@I|** Honest, my lord?
+
+**@O|** Honest--ay, honest.
+
+**@I|**
+My lord, for aught I know.
+
+**@O|** What dost thou think?
+
+**@I|** Think, my lord?
+
+**@O|**
+"Think, my lord?" By heaven, thou echo'st me
+As if there were some monster in thy thought
+Too hideous to be shown. Thou dost mean
+something.
+I heard thee say even now, thou lik'st not that,
+When @C| left my wife. What didst not like?
+And when I told thee he was of my counsel
+In my whole course of wooing, thou cried'st
+"Indeed?"
+And didst contract and purse thy brow together
+As if thou then hadst shut up in thy brain
+Some horrible conceit. If thou dost love me,
+Show me thy thought.
+
+**@I|** My lord, you know I love you.
+
+**@O|** I think thou dost\semicolon|
+And for I know thou 'rt full of love and honesty
+And weigh'st thy words before thou giv'st them
+breath,
+Therefore these stops of thine fright me the more.
+For such things in a false, disloyal knave
+Are tricks of custom\semicolon| but in a man that's just,
+They're close dilations working from the heart
+That passion cannot rule.
+
+**@I|** For Michael @C|,
+I dare be sworn I think that he is honest.
+
+**@O|**
+I think so too.
+
+**@I|** Men should be what they seem\semicolon|
+Or those that be not, would they might seem none!
+
+**@O|** Certain, men should be what they seem.
+
+**@I|**
+Why then, I think @C|'s an honest man.
+
+**@O|** Nay, yet there's more in this.
+I prithee speak to me as to thy thinkings,
+As thou dost ruminate, and give thy worst of
+thoughts
+The worst of words.
+
+**@I|** Good my lord, pardon me.
+Though I am bound to every act of duty,
+I am not bound to that all slaves are free to.
+Utter my thoughts? Why, say they are vile and
+false--
+As where's that palace whereinto foul things
+Sometimes intrude not? Who has that breast so
+pure
+But some uncleanly apprehensions
+Keep leets and law days and in sessions sit
+With meditations lawful?
+
+**@O|**
+Thou dost conspire against thy friend, @I|,
+If thou but think'st him wronged and mak'st his ear
+A stranger to thy thoughts.
+
+**@I|** I do beseech you,
+Though I perchance am vicious in my guess--
+As, I confess, it is my nature's plague
+To spy into abuses, and oft my jealousy
+Shapes faults that are not--that your wisdom
+From one that so imperfectly conceits
+Would take no notice, nor build yourself a trouble
+Out of his scattering and unsure observance.
+It were not for your quiet nor your good,
+Nor for my manhood, honesty, and wisdom,
+To let you know my thoughts.
+
+**@O|** What dost thou mean?
+
+**@I|**
+Good name in man and woman, dear my lord,
+Is the immediate jewel of their souls.
+Who steals my purse steals trash. 'Tis something,
+nothing\semicolon|
+'Twas mine, 'tis his, and has been slave to
+thousands.
+But he that filches from me my good name
+Robs me of that which not enriches him
+And makes me poor indeed.
+
+**@O|** By heaven, I'll know thy thoughts.
+
+**@I|**
+You cannot, if my heart were in your hand,
+Nor shall not, whilst 'tis in my custody.
+
+**@O|**
+Ha?
+
+**@I|** O, beware, my lord, of jealousy!
+It is the green-eyed monster which doth mock
+The meat it feeds on. That cuckold lives in bliss
+Who, certain of his fate, loves not his wronger\semicolon|
+But O, what damned minutes tells he o'er
+Who dotes, yet doubts\semicolon| suspects, yet strongly loves!
+
+**@O|** O misery!
+
+**@I|**
+Poor and content is rich, and rich enough\semicolon|
+But riches fineless is as poor as winter
+To him that ever fears he shall be poor.
+Good God, the souls of all my tribe defend
+From jealousy!
+
+**@O|** Why, why is this?
+Think'st thou I'd make a life of jealousy,
+To follow still the changes of the moon
+With fresh suspicions? No. To be once in doubt
+Is once to be resolved. Exchange me for a goat
+When I shall turn the business of my soul
+To such exsufflicate and blown surmises,
+Matching thy inference. 'Tis not to make me jealous
+To say my wife is fair, feeds well, loves company,
+Is free of speech, sings, plays, and dances well.
+Where virtue is, these are more virtuous.
+Nor from mine own weak merits will I draw
+The smallest fear or doubt of her revolt,
+For she had eyes, and chose me. No, @I|,
+I'll see before I doubt\semicolon| when I doubt, prove\semicolon|
+And on the proof, there is no more but this:
+Away at once with love or jealousy.
+
+**@I|**
+I am glad of this, for now I shall have reason
+To show the love and duty that I bear you
+With franker spirit. Therefore, as I am bound,
+Receive it from me. I speak not yet of proof.
+Look to your wife\semicolon| observe her well with @C|\semicolon|
+Wear your eyes thus, not jealous nor secure.
+I would not have your free and noble nature,
+Out of self-bounty, be abused. Look to 't.
+I know our country disposition well.
+In Venice they do let God see the pranks
+They dare not show their husbands. Their best
+conscience
+Is not to leave 't undone, but keep 't unknown.
+
+**@O|** Dost thou say so?
+
+**@I|**
+She did deceive her father, marrying you,
+And when she seemed to shake and fear your looks,
+She loved them most.
+
+**@O|** And so she did.
+
+**@I|** Why, go to, then!
+She that, so young, could give out such a seeming,
+To seel her father's eyes up close as oak,
+He thought 'twas witchcraft! But I am much to
+blame.
+I humbly do beseech you of your pardon
+For too much loving you.
+
+**@O|** I am bound to thee forever.
+
+**@I|**
+I see this hath a little dashed your spirits.
+
+**@O|**
+Not a jot, not a jot.
+
+**@I|** I' faith, I fear it has.
+I hope you will consider what is spoke
+Comes from my love. But I do see you're moved.
+I am to pray you not to strain my speech
+To grosser issues nor to larger reach
+Than to suspicion.
+
+**@O|** I will not.
+
+**@I|** Should you do so, my lord,
+My speech should fall into such vile success
+As my thoughts aim not at. @C|'s my worthy
+friend.
+My lord, I see you're moved.
+
+**@O|** No, not much moved.
+I do not think but @D|'s honest.
+
+**@I|**
+Long live she so! And long live you to think so!
+
+**@O|**
+And yet, how nature erring from itself--
+
+**@I|**
+Ay, there's the point. As, to be bold with you,
+Not to affect many proposed matches
+Of her own clime, complexion, and degree,
+Whereto we see in all things nature tends--
+Foh! One may smell in such a will most rank,
+Foul disproportion, thoughts unnatural--
+But pardon me--I do not in position
+Distinctly speak of her, though I may fear
+Her will, recoiling to her better judgment,
+May fall to match you with her country forms
+And happily repent.
+
+**@O|** Farewell, farewell!
+If more thou dost perceive, let me know more.
+Set on thy wife to observe. Leave me, @I|.
+
+**@I|**, \lbracket|beginning to exit\rbracket| My lord, I take my leave.
+
+**@O|**
+Why did I marry? This honest creature doubtless
+Sees and knows more, much more, than he unfolds.
+
+**@I|**, \lbracket|returning\rbracket|
+My lord, I would I might entreat your Honor
+To scan this thing no farther. Leave it to time.
+Although 'tis fit that @C| have his place--
+For sure he fills it up with great ability--
+Yet, if you please to hold him off awhile,
+You shall by that perceive him and his means.
+Note if your lady strain his entertainment
+With any strong or vehement importunity.
+Much will be seen in that. In the meantime,
+Let me be thought too busy in my fears--
+As worthy cause I have to fear I am--
+And hold her free, I do beseech your Honor.
+
+**@O|** Fear not my government.
+
+**@I|** I once more take my leave. \lbracket|He exits.\rbracket|
+
+**@O|**
+This fellow's of exceeding honesty,
+And knows all qualities with a learned spirit
+Of human dealings. If I do prove her haggard,
+Though that her jesses were my dear heartstrings,
+I'd whistle her off and let her down the wind
+To prey at fortune. Haply, for I am black
+And have not those soft parts of conversation
+That chamberers have, or for I am declined
+Into the vale of years--yet that's not much--
+She's gone, I am abused, and my relief
+Must be to loathe her. O curse of marriage,
+That we can call these delicate creatures ours
+And not their appetites! I had rather be a toad
+And live upon the vapor of a dungeon
+Than keep a corner in the thing I love
+For others' uses. Yet 'tis the plague of great ones\semicolon|
+Prerogatived are they less than the base.
+'Tis destiny unshunnable, like death.
+Even then this forked plague is fated to us
+When we do quicken. Look where she comes.
+
+\lbracket|Enter @D| and @E|.\rbracket|
+
+If she be false, heaven mocks itself!
+I'll not believe 't.
+
+**@D|** How now, my dear @O|?
+Your dinner, and the generous islanders
+By you invited, do attend your presence.
+
+**@O|** I am to blame.
+
+**@D|**
+Why do you speak so faintly? Are you not well?
+
+**@O|**
+I have a pain upon my forehead, here.
+
+**@D|**
+Faith, that's with watching. 'Twill away again.
+Let me but bind it hard\semicolon| within this hour
+It will be well.
+
+**@O|** Your napkin is too little.
+Let it alone. \lbracket|The handkerchief falls, unnoticed.\rbracket|
+Come, I'll go in with you.
+
+**@D|**
+I am very sorry that you are not well.
+\lbracket|@O| and @D| exit.\rbracket|
+
+**@E|**, \lbracket|picking up the handkerchief\rbracket|
+I am glad I have found this napkin.
+This was her first remembrance from the Moor.
+My wayward husband hath a hundred times
+Wooed me to steal it. But she so loves the token
+(For he conjured her she should ever keep it)
+That she reserves it evermore about her
+To kiss and talk to. I'll have the work ta'en out
+And give 't @I|. What he will do with it
+Heaven knows, not I.
+I nothing but to please his fantasy.
+
+\lbracket|Enter @I|.\rbracket|
+
+
+**@I|** How now? What do you here alone?
+
+**@E|**
+Do not you chide. I have a thing for you.
+
+**@I|**
+You have a thing for me? It is a common thing--
+
+**@E|** Ha?
+
+**@I|** To have a foolish wife.
+
+**@E|**
+O, is that all? What will you give me now
+For that same handkerchief?
+
+**@I|** What handkerchief?
+
+**@E|** What handkerchief?
+Why, that the Moor first gave to @D|,
+That which so often you did bid me steal.
+
+**@I|** Hast stol'n it from her?
+
+**@E|**
+No, faith, she let it drop by negligence,
+And to th' advantage I, being here, took 't up.
+Look, here 'tis.
+
+**@I|** A good wench! Give it me.
+
+**@E|**
+What will you do with 't, that you have been so
+earnest
+To have me filch it?
+
+**@I|**, \lbracket|snatching it\rbracket| Why, what is that to you?
+
+**@E|**
+If it be not for some purpose of import,
+Give 't me again. Poor lady, she'll run mad
+When she shall lack it.
+
+**@I|** Be not acknown on 't.
+I have use for it. Go, leave me. \lbracket|@E| exits.\rbracket|
+I will in @C|'s lodging lose this napkin
+And let him find it. Trifles light as air
+Are to the jealous confirmations strong
+As proofs of holy writ. This may do something.
+The Moor already changes with my poison\semicolon|
+Dangerous conceits are in their natures poisons,
+Which at the first are scarce found to distaste,
+But with a little act upon the blood
+Burn like the mines of sulfur.
+
+\lbracket|Enter @O|.\rbracket|
+
+I did say so.
+Look where he comes. Not poppy nor mandragora
+Nor all the drowsy syrups of the world
+Shall ever medicine thee to that sweet sleep
+Which thou owedst yesterday.
+
+**@O|** Ha, ha, false to me?
+
+**@I|**
+Why, how now, general? No more of that!
+
+**@O|**
+Avaunt! Begone! Thou hast set me on the rack.
+I swear 'tis better to be much abused
+Than but to know 't a little.
+
+**@I|** How now, my lord?
+
+**@O|**
+What sense had I of her stol'n hours of lust?
+I saw 't not, thought it not\semicolon| it harmed not me.
+I slept the next night well, fed well, was free and
+merry.
+I found not @C|'s kisses on her lips.
+He that is robbed, not wanting what is stol'n,
+Let him not know 't, and he's not robbed at all.
+
+**@I|** I am sorry to hear this.
+
+**@O|**
+I had been happy if the general camp,
+Pioners and all, had tasted her sweet body,
+So I had nothing known. O, now, forever
+Farewell the tranquil mind! Farewell content!
+Farewell the plumed troops and the big wars
+That makes ambition virtue! O, farewell!
+Farewell the neighing steed and the shrill trump,
+The spirit-stirring drum, th' ear-piercing fife,
+The royal banner, and all quality,
+Pride, pomp, and circumstance of glorious war!
+And O you mortal engines, whose rude throats
+Th' immortal Jove's dread clamors counterfeit,
+Farewell! @O|'s occupation's gone!
+
+**@I|** Is 't possible, my lord?
+
+**@O|**
+Villain, be sure thou prove my love a whore!
+Be sure of it. Give me the ocular proof,
+Or, by the worth of mine eternal soul,
+Thou hadst been better have been born a dog
+Than answer my waked wrath.
+
+**@I|** Is 't come to this?
+
+**@O|**
+Make me to see 't, or at the least so prove it
+That the probation bear no hinge nor loop
+To hang a doubt on, or woe upon thy life!
+
+**@I|** My noble lord--
+
+**@O|**
+If thou dost slander her and torture me,
+Never pray more. Abandon all remorse\semicolon|
+On horror's head horrors accumulate\semicolon|
+Do deeds to make heaven weep, all Earth amazed\semicolon|
+For nothing canst thou to damnation add
+Greater than that.
+
+**@I|** O grace! O heaven forgive me!
+Are you a man? Have you a soul or sense?
+God b' wi' you. Take mine office.--O wretched fool,
+That liv'st to make thine honesty a vice!--
+O monstrous world! Take note, take note, O world:
+To be direct and honest is not safe.--
+I thank you for this profit, and from hence
+I'll love no friend, sith love breeds such offense.
+
+**@O|** Nay, stay. Thou shouldst be honest.
+
+**@I|**
+I should be wise\semicolon| for honesty's a fool
+And loses that it works for.
+
+**@O|** By the world,
+I think my wife be honest and think she is not.
+I think that thou art just and think thou art not.
+I'll have some proof! Her name, that was as fresh
+As Dian's visage, is now begrimed and black
+As mine own face. If there be cords, or knives,
+Poison, or fire, or suffocating streams,
+I'll not endure it. Would I were satisfied!
+
+**@I|**
+I see you are eaten up with passion.
+I do repent me that I put it to you.
+You would be satisfied?
+
+**@O|** Would? Nay, and I will.
+
+**@I|**
+And may\semicolon| but how? How satisfied, my lord?
+Would you, the supervisor, grossly gape on,
+Behold her topped?
+
+**@O|** Death and damnation! O!
+
+**@I|**
+It were a tedious difficulty, I think,
+To bring them to that prospect. Damn them then
+If ever mortal eyes do see them bolster
+More than their own! What then? How then?
+What shall I say? Where's satisfaction?
+It is impossible you should see this,
+Were they as prime as goats, as hot as monkeys,
+As salt as wolves in pride, and fools as gross
+As ignorance made drunk. But yet I say,
+If imputation and strong circumstances
+Which lead directly to the door of truth
+Will give you satisfaction, you might have 't.
+
+**@O|**
+Give me a living reason she's disloyal.
+
+**@I|** I do not like the office,
+But sith I am entered in this cause so far,
+Pricked to 't by foolish honesty and love,
+I will go on. I lay with @C| lately,
+And being troubled with a raging tooth
+I could not sleep. There are a kind of men
+So loose of soul that in their sleeps will mutter
+Their affairs. One of this kind is @C|.
+In sleep I heard him say "Sweet @D|,
+Let us be wary, let us hide our loves."
+And then, sir, would he gripe and wring my hand,
+Cry "O sweet creature!" then kiss me hard,
+As if he plucked up kisses by the roots
+That grew upon my lips\semicolon| then laid his leg
+O'er my thigh, and sighed, and kissed, and then
+Cried "Cursed fate that gave thee to the Moor!"
+
+**@O|**
+O monstrous! Monstrous!
+
+**@I|** Nay, this was but his
+dream.
+
+**@O|**
+But this denoted a foregone conclusion.
+'Tis a shrewd doubt, though it be but a dream.
+
+**@I|**
+And this may help to thicken other proofs
+That do demonstrate thinly.
+
+**@O|** I'll tear her all to pieces.
+
+**@I|**
+Nay, but be wise. Yet we see nothing done.
+She may be honest yet. Tell me but this:
+Have you not sometimes seen a handkerchief
+Spotted with strawberries in your wife's hand?
+
+**@O|**
+I gave her such a one. 'Twas my first gift.
+
+**@I|**
+I know not that\semicolon| but such a handkerchief--
+I am sure it was your wife's--did I today
+See @C| wipe his beard with.
+
+**@O|** If it be that--
+
+**@I|**
+If it be that, or any that was hers,
+It speaks against her with the other proofs.
+
+**@O|**
+O, that the slave had forty thousand lives!
+One is too poor, too weak for my revenge.
+Now do I see 'tis true. Look here, @I|,
+All my fond love thus do I blow to heaven.
+'Tis gone.
+Arise, black vengeance, from the hollow hell!
+Yield up, O love, thy crown and hearted throne
+To tyrannous hate! Swell, bosom, with thy fraught,
+For 'tis of aspics' tongues!
+
+**@I|** Yet be content.
+
+**@O|** O, blood, blood, blood!
+
+**@I|**
+Patience, I say. Your mind perhaps may change.
+
+**@O|**
+Never, @I|. Like to the Pontic Sea,
+Whose icy current and compulsive course
+Ne'er feels retiring ebb, but keeps due on
+To the Propontic and the Hellespont,
+Even so my bloody thoughts, with violent pace
+Shall ne'er look back, ne'er ebb to humble love,
+Till that a capable and wide revenge
+Swallow them up. \lbracket|He kneels.\rbracket| Now by yond marble
+heaven,
+In the due reverence of a sacred vow,
+I here engage my words.
+
+**@I|** Do not rise yet. \lbracket|@I| kneels.\rbracket|
+Witness, you ever-burning lights above,
+You elements that clip us round about,
+Witness that here @I| doth give up
+The execution of his wit, hands, heart
+To wronged @O|'s service! Let him command,
+And to obey shall be in me remorse,
+What bloody business ever. \lbracket|They rise.\rbracket|
+
+**@O|** I greet thy love
+Not with vain thanks but with acceptance
+bounteous,
+And will upon the instant put thee to 't.
+Within these three days let me hear thee say
+That @C|'s not alive.
+
+**@I|** My friend is dead.
+'Tis done at your request. But let her live.
+
+**@O|** Damn her, lewd minx! O, damn her, damn
+her!
+Come, go with me apart. I will withdraw
+To furnish me with some swift means of death
+For the fair devil. Now art thou my lieutenant.
+
+**@I|** I am your own forever.
+\lbracket|They exit.\rbracket|
+
+\h2[Scene 4]
+
+\lbracket|Enter @D|, @E|, and Clown.\rbracket|
+
+
+**@D|** Do you know, sirrah, where Lieutenant
+@C| lies?
+
+**CLOWN** I dare not say he lies anywhere.
+
+**@D|** Why, man?
+
+**CLOWN** He's a soldier, and for me to say a soldier lies,
+'tis stabbing.
+
+**@D|** Go to! Where lodges he?
+
+**CLOWN** To tell you where he lodges is to tell you
+where I lie.
+
+**@D|** Can anything be made of this?
+
+**CLOWN** I know not where he lodges\semicolon| and for me to
+devise a lodging and say he lies here, or he lies
+there, were to lie in mine own throat.
+
+**@D|** Can you inquire him out, and be edified
+by report?
+
+**CLOWN** I will catechize the world for him--that is,
+make questions, and by them answer.
+
+**@D|** Seek him, bid him come hither. Tell him I
+have moved my lord on his behalf and hope all will
+be well.
+
+**CLOWN** To do this is within the compass of man's wit,
+and therefore I will attempt the doing it.
+\lbracket|Clown exits.\rbracket|
+
+**@D|**
+Where should I lose that handkerchief, @E|?
+
+**@E|** I know not, madam.
+
+**@D|**
+Believe me, I had rather have lost my purse
+Full of crusadoes. And but my noble Moor
+Is true of mind and made of no such baseness
+As jealous creatures are, it were enough
+To put him to ill thinking.
+
+**@E|** Is he not jealous?
+
+**@D|**
+Who, he? I think the sun where he was born
+Drew all such humors from him.
+
+**@E|** Look where he
+comes.
+
+\lbracket|Enter @O|.\rbracket|
+
+
+**@D|**
+I will not leave him now till @C|
+Be called to him.--How is 't with you, my lord?
+
+**@O|**
+Well, my good lady. \lbracket|Aside.\rbracket| O, hardness to
+dissemble!--
+How do you, @D|?
+
+**@D|** Well, my good lord.
+
+**@O|**
+Give me your hand. \lbracket|He takes her hand.\rbracket| This hand
+is moist, my lady.
+
+**@D|**
+It yet has felt no age nor known no sorrow.
+
+**@O|**
+This argues fruitfulness and liberal heart.
+Hot, hot, and moist. This hand of yours requires
+A sequester from liberty, fasting and prayer,
+Much castigation, exercise devout\semicolon|
+For here's a young and sweating devil here
+That commonly rebels. 'Tis a good hand,
+A frank one.
+
+**@D|** You may indeed say so,
+For 'twas that hand that gave away my heart.
+
+**@O|**
+A liberal hand! The hearts of old gave hands,
+But our new heraldry is hands, not hearts.
+
+**@D|**
+I cannot speak of this. Come now, your promise.
+
+**@O|** What promise, chuck?
+
+**@D|**
+I have sent to bid @C| come speak with you.
+
+**@O|**
+I have a salt and sorry rheum offends me.
+Lend me thy handkerchief.
+
+**@D|** Here, my lord.
+
+**@O|**
+That which I gave you.
+
+**@D|** I have it not about me.
+
+**@O|** Not?
+
+**@D|** No, faith, my lord.
+
+**@O|** That's a fault. That handkerchief
+Did an Egyptian to my mother give.
+She was a charmer, and could almost read
+The thoughts of people. She told her, while she kept
+it,
+'Twould make her amiable and subdue my father
+Entirely to her love. But if she lost it,
+Or made a gift of it, my father's eye
+Should hold her loathed, and his spirits should hunt
+After new fancies. She, dying, gave it me,
+And bid me, when my fate would have me wived,
+To give it her. I did so\semicolon| and take heed on 't,
+Make it a darling like your precious eye.
+To lose 't or give 't away were such perdition
+As nothing else could match.
+
+**@D|** Is 't possible?
+
+**@O|**
+'Tis true. There's magic in the web of it.
+A sybil that had numbered in the world
+The sun to course two hundred compasses,
+In her prophetic fury sewed the work.
+The worms were hallowed that did breed the silk,
+And it was dyed in mummy, which the skillful
+Conserved of maidens' hearts.
+
+**@D|** I' faith, is 't true?
+
+**@O|**
+Most veritable. Therefore, look to 't well.
+
+**@D|**
+Then would to God that I had never seen 't!
+
+**@O|** Ha? Wherefore?
+
+**@D|**
+Why do you speak so startingly and rash?
+
+**@O|**
+Is 't lost? Is 't gone? Speak, is 't out o' th' way?
+
+**@D|** Heaven bless us!
+
+**@O|** Say you?
+
+**@D|**
+It is not lost, but what an if it were?
+
+**@O|** How?
+
+**@D|** I say it is not lost.
+
+**@O|** Fetch 't. Let me see 't!
+
+**@D|**
+Why, so I can. But I will not now.
+This is a trick to put me from my suit.
+Pray you, let @C| be received again.
+
+**@O|**
+Fetch me the handkerchief! \lbracket|Aside.\rbracket| My mind
+misgives.
+
+**@D|** Come, come.
+You'll never meet a more sufficient man.
+
+**@O|**
+The handkerchief!
+
+**@D|** I pray, talk me of @C|.
+
+**@OT**he handkerchief!
+
+**@D|** A man that all his time
+Hath founded his good fortunes on your love\semicolon|
+Shared dangers with you--
+
+**@O|**
+The handkerchief!
+
+**@D|** I' faith, you are to blame.
+
+**@O|** Zounds! \lbracket|@O| exits.\rbracket|
+
+**@E|** Is not this man jealous?
+
+**@D|** I ne'er saw this before.
+Sure, there's some wonder in this handkerchief!
+I am most unhappy in the loss of it.
+
+**@E|**
+'Tis not a year or two shows us a man.
+They are all but stomachs, and we all but food\semicolon|
+They eat us hungerly, and when they are full
+They belch us.
+
+\lbracket|Enter @I| and @C|.\rbracket|
+
+Look you--@C| and my husband.
+
+**@I|**, \lbracket|to @C|\rbracket|
+There is no other way\semicolon| 'tis she must do 't,
+And, lo, the happiness! Go and importune her.
+
+**@D|**
+How now, good @C|, what's the news with you?
+
+**@C|**
+Madam, my former suit. I do beseech you
+That by your virtuous means I may again
+Exist, and be a member of his love
+Whom I with all the office of my heart
+Entirely honor. I would not be delayed.
+If my offense be of such mortal kind
+That nor my service past nor present sorrows
+Nor purposed merit in futurity
+Can ransom me into his love again,
+But to know so must be my benefit.
+So shall I clothe me in a forced content,
+And shut myself up in some other course
+To fortune's alms.
+
+**@D|** Alas, thrice-gentle @C|,
+My advocation is not now in tune.
+My lord is not my lord\semicolon| nor should I know him
+Were he in favor as in humor altered.
+So help me every spirit sanctified
+As I have spoken for you all my best,
+And stood within the blank of his displeasure
+For my free speech! You must awhile be patient.
+What I can do I will\semicolon| and more I will
+Than for myself I dare. Let that suffice you.
+
+**@I|**
+Is my lord angry?
+
+**@E|** He went hence but now,
+And certainly in strange unquietness.
+
+**@I|**
+Can he be angry? I have seen the cannon
+When it hath blown his ranks into the air
+And, like the devil, from his very arm
+Puffed his own brother--and is he angry?
+Something of moment then. I will go meet him.
+There's matter in 't indeed if he be angry.
+
+**@D|**
+I prithee do so. \lbracket|He exits.\rbracket|
+Something, sure, of state,
+Either from Venice, or some unhatched practice
+Made demonstrable here in Cyprus to him,
+Hath puddled his clear spirit\semicolon| and in such cases
+Men's natures wrangle with inferior things,
+Though great ones are their object. 'Tis even so.
+For let our finger ache, and it endues
+Our other healthful members even to a sense
+Of pain. Nay, we must think men are not gods,
+Nor of them look for such observancy
+As fits the bridal. Beshrew me much, @E|,
+I was--unhandsome warrior as I am!--
+Arraigning his unkindness with my soul.
+But now I find I had suborned the witness,
+And he's indicted falsely.
+
+**@E|** Pray heaven it be
+State matters, as you think, and no conception
+Nor no jealous toy concerning you.
+
+**@D|**
+Alas the day, I never gave him cause!
+
+**@E|**
+But jealous souls will not be answered so.
+They are not ever jealous for the cause,
+But jealous for they're jealous. It is a monster
+Begot upon itself, born on itself.
+
+**@D|**
+Heaven keep that monster from @O|'s mind!
+
+**@E|** Lady, amen.
+
+**@D|**
+I will go seek him.--@C|, walk hereabout.
+If I do find him fit, I'll move your suit
+And seek to effect it to my uttermost.
+
+**@C|** I humbly thank your Ladyship.
+\lbracket|@D| and @E| exit.\rbracket|
+
+\lbracket|Enter @BI|.\rbracket|
+
+
+**@BI|**
+'Save you, friend @C|!
+
+**@C|** What make you from
+home?
+How is 't with you, my most fair @BI|?
+I' faith, sweet love, I was coming to your house.
+
+**@BI|**
+And I was going to your lodging, @C|.
+What, keep a week away? Seven days and nights,
+Eightscore eight hours, and lovers' absent hours
+More tedious than the dial eightscore times?
+O weary reck'ning!
+
+**@C|** Pardon me, @BI|.
+I have this while with leaden thoughts been pressed,
+But I shall in a more continuate time
+Strike off this score of absence. Sweet @BI|,
+\lbracket|Giving her @D|'s handkerchief.\rbracket|
+Take me this work out.
+
+**@BI|** O, @C|, whence came this?
+This is some token from a newer friend.
+To the felt absence now I feel a cause.
+Is 't come to this? Well, well.
+
+**@C|** Go to, woman!
+Throw your vile guesses in the devil's teeth,
+From whence you have them. You are jealous now
+That this is from some mistress, some
+remembrance.
+No, by my faith, @BI|.
+
+**@BI|** Why, whose is it?
+
+**@C|**
+I know not neither. I found it in my chamber.
+I like the work well. Ere it be demanded,
+As like enough it will, I would have it copied.
+Take it, and do 't, and leave me for this time.
+
+**@BI|** Leave you? Wherefore?
+
+**@C|**
+I do attend here on the General,
+And think it no addition, nor my wish,
+To have him see me womaned.
+
+**@BI|** Why, I pray you?
+
+**@C|** Not that I love you not.
+
+**@BI|** But that you do not love me!
+I pray you bring me on the way a little,
+And say if I shall see you soon at night.
+
+**@C|**
+'Tis but a little way that I can bring you,
+For I attend here. But I'll see you soon.
+
+**@BI|**
+'Tis very good. I must be circumstanced.
+\lbracket|They exit.\rbracket|
+
+\h1[Act 4]
+
+\h2[Scene 1]
+
+\lbracket|Enter @O| and @I|.\rbracket|
+
+
+**@I|**
+Will you think so?
+
+**@O|** Think so, @I|?
+
+**@I|** What,
+To kiss in private?
+
+**@O|** An unauthorized kiss!
+
+**@I|**
+Or to be naked with her friend in bed
+An hour or more, not meaning any harm?
+
+**@O|**
+Naked in bed, @I|, and not mean harm?
+It is hypocrisy against the devil!
+They that mean virtuously, and yet do so,
+The devil their virtue tempts, and they tempt
+heaven.
+
+**@I|**
+If they do nothing, 'tis a venial slip.
+But if I give my wife a handkerchief--
+
+**@O|** What then?
+
+**@I|**
+Why then, 'tis hers, my lord, and being hers,
+She may, I think, bestow 't on any man.
+
+**@O|**
+She is protectress of her honor, too.
+May she give that?
+
+**@I|**
+Her honor is an essence that's not seen\semicolon|
+They have it very oft that have it not.
+But for the handkerchief--
+
+**@O|**
+By heaven, I would most gladly have forgot it.
+Thou saidst--O, it comes o'er my memory
+As doth the raven o'er the infectious house,
+Boding to all--he had my handkerchief.
+
+**@I|**
+Ay, what of that?
+
+**@O|** That's not so good now.
+
+**@I|** What
+If I had said I had seen him do you wrong?
+Or heard him say (as knaves be such abroad,
+Who having, by their own importunate suit
+Or voluntary dotage of some mistress,
+Convinced or supplied them, cannot choose
+But they must blab)--
+
+**@O|** Hath he said anything?
+
+**@I|**
+He hath, my lord, but be you well assured,
+No more than he'll unswear.
+
+**@O|** What hath he said?
+
+**@I|**
+Faith, that he did--I know not what he did.
+
+**@O|** What? What?
+
+**@I|**
+Lie--
+
+**@O|** With her?
+
+**@I|** With her--on her--what you will.
+
+**@O|** Lie with her? Lie on her? We say "lie on her"
+when they belie her. Lie with her--Zounds, that's
+fulsome! Handkerchief--confessions--handkerchief.
+To confess and be hanged for his labor.
+First to be hanged and then to confess--I tremble
+at it. Nature would not invest herself in such shadowing
+passion without some instruction. It is not
+words that shakes me thus. Pish! Noses, ears, and
+lips--is 't possible? Confess--handkerchief--O,
+devil! \lbracket|He falls in a trance.\rbracket|
+
+**@I|** Work on,
+My medicine, work! Thus credulous fools are
+caught,
+And many worthy and chaste dames even thus,
+All guiltless, meet reproach.--What ho! My lord!
+My lord, I say. @O|!
+
+\lbracket|Enter @C|.\rbracket|
+
+How now, @C|?
+
+**@C|** What's the matter?
+
+**@I|**
+My lord is fall'n into an epilepsy.
+This is his second fit. He had one yesterday.
+
+**@C|**
+Rub him about the temples.
+
+**@I|** No, forbear.
+The lethargy must have his quiet course.
+If not, he foams at mouth, and by and by
+Breaks out to savage madness. Look, he stirs.
+Do you withdraw yourself a little while.
+He will recover straight. When he is gone,
+I would on great occasion speak with you.
+\lbracket|@C| exits.\rbracket|
+How is it, general? Have you not hurt your head?
+
+**@O|**
+Dost thou mock me?
+
+**@I|** I mock you not, by heaven!
+Would you would bear your fortune like a man!
+
+**@O|**
+A horned man's a monster and a beast.
+
+**@I|**
+There's many a beast, then, in a populous city,
+And many a civil monster.
+
+**@O|**
+Did he confess it?
+
+**@I|** Good sir, be a man!
+Think every bearded fellow that's but yoked
+May draw with you. There's millions now alive
+That nightly lie in those unproper beds
+Which they dare swear peculiar. Your case is better.
+O, 'tis the spite of hell, the fiend's arch-mock,
+To lip a wanton in a secure couch
+And to suppose her chaste! No, let me know,
+And knowing what I am, I know what she shall be.
+
+**@O|** O, thou art wise, 'tis certain.
+
+**@I|** Stand you awhile apart.
+Confine yourself but in a patient list.
+Whilst you were here, o'erwhelmed with your grief--
+A passion most unsuiting such a man--
+@C| came hither. I shifted him away
+And laid good 'scuses upon your ecstasy,
+Bade him anon return and here speak with me,
+The which he promised. Do but encave yourself,
+And mark the fleers, the gibes, and notable scorns
+That dwell in every region of his face.
+For I will make him tell the tale anew--
+Where, how, how oft, how long ago, and when
+He hath and is again to cope your wife.
+I say but mark his gesture. Marry, patience,
+Or I shall say you're all in all in spleen,
+And nothing of a man.
+
+**@O|** Dost thou hear, @I|,
+I will be found most cunning in my patience,
+But (dost thou hear?) most bloody.
+
+**@I|** That's not amiss.
+But yet keep time in all. Will you withdraw?
+\lbracket|@O| withdraws.\rbracket|
+Now will I question @C| of @BI|,
+A huswife that by selling her desires
+Buys herself bread and clothes. It is a creature
+That dotes on @C|--as 'tis the strumpet's plague
+To beguile many and be beguiled by one.
+He, when he hears of her, cannot restrain
+From the excess of laughter. Here he comes.
+
+\lbracket|Enter @C|.\rbracket|
+
+As he shall smile, @O| shall go mad,
+And his unbookish jealousy must construe
+Poor @C|'s smiles, gestures, and light behaviors
+Quite in the wrong.--How do you, lieutenant?
+
+**@C|**
+The worser that you give me the addition
+Whose want even kills me.
+
+**@I|**
+Ply @D| well, and you are sure on 't.
+Now, if this suit lay in @BI|'s power,
+How quickly should you speed!
+
+**@C|**, \lbracket|laughing\rbracket| Alas, poor caitiff!
+
+**@O|** Look how he laughs already!
+
+**@I|** I never knew woman love man so.
+
+**@C|**
+Alas, poor rogue, I think i' faith she loves me.
+
+**@O|**
+Now he denies it faintly and laughs it out.
+
+**@I|**
+Do you hear, @C|?
+
+**@O|** Now he importunes him
+To tell it o'er. Go to, well said, well said.
+
+**@I|**
+She gives it out that you shall marry her.
+Do you intend it?
+
+**@C|** Ha, ha, ha!
+
+**@O|**
+Do you triumph, Roman? Do you triumph?
+
+**@C|** I marry her? What, a customer? Prithee bear
+some charity to my wit! Do not think it so unwholesome.
+Ha, ha, ha!
+
+**@O|** So, so, so, so. They laugh that wins.
+
+**@I|**
+Faith, the cry goes that you marry her.
+
+**@C|** Prithee say true!
+
+**@I|** I am a very villain else.
+
+**@O|** Have you scored me? Well.
+
+**@C|** This is the monkey's own giving out. She is
+persuaded I will marry her out of her own love and
+flattery, not out of my promise.
+
+**@O|**
+@I| beckons me. Now he begins the story.
+
+**@C|** She was here even now. She haunts me in
+every place. I was the other day talking on the
+sea-bank with certain Venetians, and thither comes
+the bauble. By this hand, she falls thus about my
+neck!
+
+**@O|** Crying, "O dear @C|," as it were\semicolon| his
+gesture imports it.
+
+**@C|** So hangs and lolls and weeps upon me, so
+shakes and pulls me. Ha, ha, ha!
+
+**@O|** Now he tells how she plucked him to my
+chamber.--O, I see that nose of yours, but not that
+dog I shall throw it to.
+
+**@C|** Well, I must leave her company.
+
+**@I|** Before me, look where she comes.
+
+\lbracket|Enter @BI|.\rbracket|
+
+
+**@C|** 'Tis such another fitchew--marry, a perfumed
+one!--What do you mean by this haunting
+of me?
+
+**@BI|** Let the devil and his dam haunt you! What did
+you mean by that same handkerchief you gave me
+even now? I was a fine fool to take it! I must take
+out the work? A likely piece of work, that you
+should find it in your chamber and know not who
+left it there! This is some minx's token, and I must
+take out the work! There, give it your hobbyhorse.
+Wheresoever you had it, I'll take out no work on 't.
+
+**@C|**
+How now, my sweet @BI|? How now? How now?
+
+**@O|**
+By heaven, that should be my handkerchief!
+
+**@BI|** If you'll come to supper tonight you may. If
+you will not, come when you are next prepared
+for. \lbracket|She exits.\rbracket|
+
+**@I|** After her, after her!
+
+**@C|** Faith, I must. She'll rail in the streets else.
+
+**@I|** Will you sup there?
+
+**@C|** Faith, I intend so.
+
+**@I|** Well, I may chance to see you, for I would very
+fain speak with you.
+
+**@C|** Prithee come. Will you?
+
+**@I|** Go to\semicolon| say no more. \lbracket|@C| exits.\rbracket|
+
+**@O|**, \lbracket|coming forward\rbracket| How shall I murder him,
+@I|?
+
+**@I|** Did you perceive how he laughed at his vice?
+
+**@O|** O @I|!
+
+**@I|** And did you see the handkerchief?
+
+**@O|** Was that mine?
+
+**@I|** Yours, by this hand! And to see how he prizes
+the foolish woman your wife! She gave it him, and
+he hath giv'n it his whore.
+
+**@O|** I would have him nine years a-killing! A fine
+woman, a fair woman, a sweet woman!
+
+**@I|** Nay, you must forget that.
+
+**@O|** Ay, let her rot and perish and be damned
+tonight, for she shall not live. No, my heart is turned
+to stone. I strike it, and it hurts my hand. O, the
+world hath not a sweeter creature! She might lie by
+an emperor's side and command him tasks.
+
+**@I|** Nay, that's not your way.
+
+**@O|** Hang her, I do but say what she is! So
+delicate with her needle, an admirable musician--
+O, she will sing the savageness out of a bear!
+Of so high and plenteous wit and invention!
+
+**@I|** She's the worse for all this.
+
+**@O|** O, a thousand, a thousand times!--And then
+of so gentle a condition!
+
+**@I|** Ay, too gentle.
+
+**@O|** Nay, that's certain. But yet the pity of it,
+@I|! O, @I|, the pity of it, @I|!
+
+**@I|** If you are so fond over her iniquity, give her
+patent to offend, for if it touch not you, it comes
+near nobody.
+
+**@O|** I will chop her into messes! Cuckold me?
+
+**@I|** O, 'tis foul in her.
+
+**@O|** With mine officer!
+
+**@I|** That's fouler.
+
+**@O|** Get me some poison, @I|, this night. I'll not
+expostulate with her lest her body and beauty
+unprovide my mind again. This night, @I|.
+
+**@I|** Do it not with poison. Strangle her in her bed,
+even the bed she hath contaminated.
+
+**@O|** Good, good. The justice of it pleases. Very
+good.
+
+**@I|** And for @C|, let me be his undertaker. You
+shall hear more by midnight.
+
+**@O|**
+Excellent good. \lbracket|A trumpet sounds.\rbracket|
+What trumpet is that same?
+
+**@I|** I warrant something from Venice.
+
+\lbracket|Enter @L|, @D|, and Attendants.\rbracket|
+
+'Tis @L|. This comes from the Duke.
+See, your wife's with him.
+
+**@L|** God save you, worthy general.
+
+**@O|** With all my heart, sir.
+
+**@L|**
+The Duke and the Senators of Venice greet you.
+\lbracket|He hands @O| a paper.\rbracket|
+
+**@O|**
+I kiss the instrument of their pleasures.
+
+**@D|**
+And what's the news, good cousin @L|?
+
+**@I|**
+I am very glad to see you, signior.
+Welcome to Cyprus.
+
+**@L|**
+I thank you. How does Lieutenant @C|?
+
+**@I|** Lives, sir.
+
+**@D|**
+Cousin, there's fall'n between him and my lord
+An unkind breach, but you shall make all well.
+
+**@O|** Are you sure of that?
+
+**@D|** My lord?
+
+**@O|**, \lbracket|reading\rbracket| "This fail you not to do, as you
+will"--
+
+**@L|**
+He did not call\semicolon| he's busy in the paper.
+Is there division 'twixt my lord and @C|?
+
+**@D|**
+A most unhappy one. I would do much
+T' atone them, for the love I bear to @C|.
+
+**@O|** Fire and brimstone!
+
+**@D|** My lord?
+
+**@O|** Are you wise?
+
+**@D|**
+What, is he angry?
+
+**@L|** May be the letter moved him.
+For, as I think, they do command him home,
+Deputing @C| in his government.
+
+**@D|** By my troth, I am glad on 't.
+
+**@O|** Indeed?
+
+**@D|** My lord?
+
+**@O|** I am glad to see you mad.
+
+**@D|** Why, sweet @O|!
+
+**@O|**, \lbracket|striking her\rbracket| Devil!
+
+**@D|** I have not deserved this.
+
+**@L|**
+My lord, this would not be believed in Venice,
+Though I should swear I saw 't. 'Tis very much.
+Make her amends. She weeps.
+
+**@O|** O, devil, devil!
+If that the Earth could teem with woman's tears,
+Each drop she falls would prove a crocodile.
+Out of my sight!
+
+**@D|** I will not stay to offend you.
+\lbracket|She begins to leave.\rbracket|
+
+**@L|** Truly an obedient lady.
+I do beseech your Lordship call her back.
+
+**@O|** Mistress.
+
+**@D|**, \lbracket|turning back\rbracket| My lord?
+
+**@O|** What would you with her, sir?
+
+**@L|** Who, I, my lord?
+
+**@O|**
+Ay, you did wish that I would make her turn.
+Sir, she can turn, and turn, and yet go on,
+And turn again. And she can weep, sir, weep.
+And she's obedient, as you say, obedient.
+Very obedient.--Proceed you in your tears.--
+Concerning this, sir--O, well-painted passion!--
+I am commanded home.--Get you away.
+I'll send for you anon.--Sir, I obey the mandate
+And will return to Venice.--Hence, avaunt!
+\lbracket|@D| exits.\rbracket|
+@C| shall have my place. And, sir, tonight
+I do entreat that we may sup together.
+You are welcome, sir, to Cyprus. Goats and
+monkeys! \lbracket|He exits.\rbracket|
+
+**@L|**
+Is this the noble Moor, whom our full senate
+Call all in all sufficient? Is this the nature
+Whom passion could not shake, whose solid virtue
+The shot of accident nor dart of chance
+Could neither graze nor pierce?
+
+**@I|** He is much
+changed.
+
+**@L|**
+Are his wits safe? Is he not light of brain?
+
+**@I|**
+He's that he is. I may not breathe my censure
+What he might be. If what he might he is not,
+I would to heaven he were.
+
+**@L|** What? Strike his wife?
+
+**@I|**
+'Faith, that was not so well. Yet would I knew
+That stroke would prove the worst.
+
+**@L|** Is it his use?
+Or did the letters work upon his blood
+And new-create this fault?
+
+**@I|** Alas, alas!
+It is not honesty in me to speak
+What I have seen and known. You shall observe
+him,
+And his own courses will denote him so
+That I may save my speech. Do but go after
+And mark how he continues.
+
+**@L|**
+I am sorry that I am deceived in him.
+\lbracket|They exit.\rbracket|
+
+\h2[Scene 2]
+
+\lbracket|Enter @O| and @E|.\rbracket|
+
+
+**@O|** You have seen nothing then?
+
+**@E|**
+Nor ever heard, nor ever did suspect.
+
+**@O|**
+Yes, you have seen @C| and she together.
+
+**@E|**
+But then I saw no harm, and then I heard
+Each syllable that breath made up between them.
+
+**@O|**
+What, did they never whisper?
+
+**@E|** Never, my lord.
+
+**@O|** Nor send you out o' th' way?
+
+**@E|** Never.
+
+**@O|**
+To fetch her fan, her gloves, her mask, nor nothing?
+
+**@E|** Never, my lord.
+
+**@O|** That's strange.
+
+**@E|**
+I durst, my lord, to wager she is honest,
+Lay down my soul at stake. If you think other,
+Remove your thought. It doth abuse your bosom.
+If any wretch have put this in your head,
+Let heaven requite it with the serpent's curse,
+For if she be not honest, chaste, and true,
+There's no man happy. The purest of their wives
+Is foul as slander.
+
+**@O|** Bid her come hither. Go.
+\lbracket|@E| exits.\rbracket|
+She says enough. Yet she's a simple bawd
+That cannot say as much. This is a subtle whore,
+A closet lock and key of villainous secrets.
+And yet she'll kneel and pray. I have seen her do 't.
+
+\lbracket|Enter @D| and @E|.\rbracket|
+
+
+**@D|** My lord, what is your will?
+
+**@O|**
+Pray you, chuck, come hither.
+
+**@D|** What is your
+pleasure?
+
+**@O|**
+Let me see your eyes. Look in my face.
+
+**@D|** What horrible fancy's this?
+
+**@O|**, \lbracket|to @E|\rbracket| Some of your function,
+mistress.
+Leave procreants alone, and shut the door.
+Cough, or cry "hem," if anybody come.
+Your mystery, your mystery! Nay, dispatch.
+\lbracket|@E| exits.\rbracket|
+
+**@D|**, \lbracket|kneeling\rbracket|
+Upon my knees, what doth your speech import?
+I understand a fury in your words,
+But not the words.
+
+**@O|** Why? What art thou?
+
+**@D|**
+Your wife, my lord, your true and loyal wife.
+
+**@O|** Come, swear it. Damn thyself,
+Lest, being like one of heaven, the devils themselves
+Should fear to seize thee. Therefore be double
+damned.
+Swear thou art honest.
+
+**@D|** Heaven doth truly know it.
+
+**@O|**
+Heaven truly knows that thou art false as hell.
+
+**@D|**, \lbracket|standing\rbracket|
+To whom, my lord? With whom? How am I false?
+
+**@O|**
+Ah, Desdemon, away, away, away!
+
+**@D|**
+Alas the heavy day, why do you weep?
+Am I the motive of these tears, my lord?
+If haply you my father do suspect
+An instrument of this your calling back,
+Lay not your blame on me. If you have lost him,
+I have lost him too.
+
+**@O|** Had it pleased heaven
+To try me with affliction, had they rained
+All kind of sores and shames on my bare head,
+Steeped me in poverty to the very lips,
+Given to captivity me and my utmost hopes,
+I should have found in some place of my soul
+A drop of patience. But alas, to make me
+A fixed figure for the time of scorn
+To point his slow unmoving finger at--
+Yet could I bear that too, well, very well.
+But there where I have garnered up my heart,
+Where either I must live or bear no life,
+The fountain from the which my current runs
+Or else dries up--to be discarded thence,
+Or keep it as a cistern for foul toads
+To knot and gender in--turn thy complexion there,
+Patience, thou young and rose-lipped cherubin,
+Ay, there look grim as hell.
+
+**@D|**
+I hope my noble lord esteems me honest.
+
+**@O|**
+O, ay, as summer flies are in the shambles,
+That quicken even with blowing! O thou weed,
+Who art so lovely fair, and smell'st so sweet
+That the sense aches at thee, would thou hadst
+ne'er been born!
+
+**@D|**
+Alas, what ignorant sin have I committed?
+
+**@O|**
+Was this fair paper, this most goodly book,
+Made to write "whore" upon? What committed?
+Committed? O thou public commoner,
+I should make very forges of my cheeks
+That would to cinders burn up modesty,
+Did I but speak thy deeds. What committed?
+Heaven stops the nose at it, and the moon winks\semicolon|
+The bawdy wind that kisses all it meets
+Is hushed within the hollow mine of earth
+And will not hear 't. What committed?
+Impudent strumpet!
+
+**@D|** By heaven, you do me wrong!
+
+**@O|** Are not you a strumpet?
+
+**@D|** No, as I am a Christian!
+If to preserve this vessel for my lord
+From any other foul unlawful touch
+Be not to be a strumpet, I am none.
+
+**@O|** What, not a whore?
+
+**@D|** No, as I shall be saved.
+
+**@O|** Is 't possible?
+
+**@D|**
+O, heaven forgive us!
+
+**@O|** I cry you mercy, then.
+I took you for that cunning whore of Venice
+That married with @O|.--You, mistress,
+
+\lbracket|Enter @E|.\rbracket|
+
+That have the office opposite to Saint Peter
+And keeps the gate of hell--you, you, ay, you!
+We have done our course. There's money for your
+pains. \lbracket|He gives her money.\rbracket|
+I pray you turn the key and keep our counsel.
+\lbracket|He exits.\rbracket|
+
+**@E|**
+Alas, what does this gentleman conceive?
+How do you, madam? How do you, my good lady?
+
+**@D|** Faith, half asleep.
+
+**@E|**
+Good madam, what's the matter with my lord?
+
+**@D|** With who?
+
+**@E|** Why, with my lord, madam.
+
+**@D|**
+Who is thy lord?
+
+**@E|** He that is yours, sweet lady.
+
+**@D|**
+I have none. Do not talk to me, @E|.
+I cannot weep, nor answers have I none
+But what should go by water. Prithee, tonight
+Lay on my bed my wedding sheets. Remember.
+And call thy husband hither.
+
+**@E|** Here's a change indeed. \lbracket|She exits.\rbracket|
+
+**@D|**
+'Tis meet I should be used so, very meet.
+How have I been behaved that he might stick
+The small'st opinion on my least misuse?
+
+\lbracket|Enter @I| and @E|.\rbracket|
+
+
+**@I|**
+What is your pleasure, madam? How is 't with you?
+
+**@D|**
+I cannot tell. Those that do teach young babes
+Do it with gentle means and easy tasks.
+He might have chid me so, for, in good faith,
+I am a child to chiding.
+
+**@I|** What is the matter, lady?
+
+**@E|**
+Alas, @I|, my lord hath so bewhored her,
+Thrown such despite and heavy terms upon her
+As true hearts cannot bear.
+
+**@D|**
+Am I that name, @I|?
+
+**@I|** What name, fair
+lady?
+
+**@D|**
+Such as she said my lord did say I was.
+
+**@E|**
+He called her "whore." A beggar in his drink
+Could not have laid such terms upon his callet.
+
+**@I|** Why did he so?
+
+**@D|**
+I do not know. I am sure I am none such.
+
+**@I|**
+Do not weep, do not weep! Alas the day!
+
+**@E|**
+Hath she forsook so many noble matches,
+Her father and her country and her friends,
+To be called "whore"? Would it not make one
+weep?
+
+**@D|** It is my wretched fortune.
+
+**@I|**
+Beshrew him for 't! How comes this trick upon him?
+
+**@D|** Nay, heaven doth know.
+
+**@E|**
+I will be hanged if some eternal villain,
+Some busy and insinuating rogue,
+Some cogging, cozening slave, to get some office,
+Have not devised this slander. I will be hanged else.
+
+**@I|**
+Fie, there is no such man. It is impossible.
+
+**@D|**
+If any such there be, heaven pardon him.
+
+**@E|**
+A halter pardon him, and hell gnaw his bones!
+Why should he call her "whore"? Who keeps her
+company?
+What place? What time? What form? What
+likelihood?
+The Moor's abused by some most villainous knave,
+Some base notorious knave, some scurvy fellow.
+O heaven, that such companions thou 'dst unfold,
+And put in every honest hand a whip
+To lash the rascals naked through the world,
+Even from the east to th' west!
+
+**@I|** Speak within door.
+
+**@E|**
+O, fie upon them! Some such squire he was
+That turned your wit the seamy side without
+And made you to suspect me with the Moor.
+
+**@I|**
+You are a fool. Go to!
+
+**@D|** Alas, @I|,
+What shall I do to win my lord again?
+Good friend, go to him. For by this light of heaven,
+I know not how I lost him. \lbracket|She kneels.\rbracket| Here I
+kneel.
+If e'er my will did trespass 'gainst his love,
+Either in discourse of thought or actual deed,
+Or that mine eyes, mine ears, or any sense
+Delighted them in any other form,
+Or that I do not yet, and ever did,
+And ever will--though he do shake me off
+To beggarly divorcement--love him dearly,
+Comfort forswear me! \lbracket|She stands.\rbracket| Unkindness may
+do much,
+And his unkindness may defeat my life,
+But never taint my love. I cannot say "whore"--
+It does abhor me now I speak the word.
+To do the act that might the addition earn,
+Not the world's mass of vanity could make me.
+
+**@I|**
+I pray you be content. 'Tis but his humor.
+The business of the state does him offense,
+And he does chide with you.
+
+**@D|**
+If 'twere no other--
+
+**@I|** It is but so, I warrant.
+\lbracket|Trumpets sound.\rbracket|
+Hark how these instruments summon to supper.
+The messengers of Venice stays the meat.
+Go in and weep not. All things shall be well.
+\lbracket|@D| and @E| exit.\rbracket|
+
+\lbracket|Enter @R|.\rbracket|
+
+How now, @R|?
+
+**@R|** I do not find
+That thou deal'st justly with me.
+
+**@I|** What in the contrary?
+
+**@R|** Every day thou daff'st me with some device,
+@I|, and rather, as it seems to me now,
+keep'st from me all conveniency than suppliest me
+with the least advantage of hope. I will indeed no
+longer endure it. Nor am I yet persuaded to put up
+in peace what already I have foolishly suffered.
+
+**@I|** Will you hear me, @R|?
+
+**@R|** Faith, I have heard too much, and your
+words and performances are no kin together.
+
+**@I|** You charge me most unjustly.
+
+**@R|** With naught but truth. I have wasted myself
+out of my means. The jewels you have had
+from me to deliver to @D| would half have
+corrupted a votaress. You have told me she hath
+received them, and returned me expectations and
+comforts of sudden respect and acquaintance, but I
+find none.
+
+**@I|** Well, go to! Very well.
+
+**@R|** "Very well." "Go to!" I cannot go to, man,
+nor 'tis not very well! By this hand, I say 'tis very
+scurvy, and begin to find myself fopped in it.
+
+**@I|** Very well.
+
+**@R|** I tell you 'tis not very well! I will make
+myself known to @D|. If she will return me
+my jewels, I will give over my suit and repent my
+unlawful solicitation. If not, assure yourself I will
+seek satisfaction of you.
+
+**@I|** You have said now.
+
+**@R|** Ay, and said nothing but what I protest
+intendment of doing.
+
+**@I|** Why, now I see there's mettle in thee, and even
+from this instant do build on thee a better opinion
+than ever before. Give me thy hand, @R|.
+Thou hast taken against me a most just exception,
+but yet I protest I have dealt most directly in thy
+affair.
+
+**@R|** It hath not appeared.
+
+**@I|** I grant indeed it hath not appeared, and your
+suspicion is not without wit and judgment. But,
+@R|, if thou hast that in thee indeed which I
+have greater reason to believe now than ever--I
+mean purpose, courage, and valor--this night show
+it. If thou the next night following enjoy not @D|,
+take me from this world with treachery and
+devise engines for my life.
+
+**@R|** Well, what is it? Is it within reason and
+compass?
+
+**@I|** Sir, there is especial commission come from
+Venice to depute @C| in @O|'s place.
+
+**@R|** Is that true? Why, then, @O| and @D|
+return again to Venice.
+
+**@I|** O, no. He goes into Mauritania and takes away
+with him the fair @D|, unless his abode be
+lingered here by some accident--wherein none
+can be so determinate as the removing of @C|.
+
+**@R|** How do you mean, removing him?
+
+**@I|** Why, by making him uncapable of @O|'s
+place: knocking out his brains.
+
+**@R|** And that you would have me to do?
+
+**@I|** Ay, if you dare do yourself a profit and a right. He
+sups tonight with a harlotry, and thither will I go to
+him. He knows not yet of his honorable fortune. If
+you will watch his going thence (which I will
+fashion to fall out between twelve and one), you may
+take him at your pleasure. I will be near to second
+your attempt, and he shall fall between us. Come,
+stand not amazed at it, but go along with me. I will
+show you such a necessity in his death that you shall
+think yourself bound to put it on him. It is now high
+supper time, and the night grows to waste. About it!
+
+**@R|** I will hear further reason for this.
+
+**@I|** And you shall be satisfied.
+\lbracket|They exit.\rbracket|
+
+\h2[Scene 3]
+
+\lbracket|Enter @O|, @L|, @D|, @E|, and
+Attendants.\rbracket|
+
+
+**@L|**
+I do beseech you, sir, trouble yourself no further.
+
+**@O|**
+O, pardon me, 'twill do me good to walk.
+
+**@L|**
+Madam, good night. I humbly thank your Ladyship.
+
+**@D|** Your Honor is most welcome.
+
+**@O|**
+Will you walk, sir?--O, @D|--
+
+**@D|** My lord?
+
+**@O|** Get you to bed on th' instant. I will be
+returned forthwith. Dismiss your attendant there.
+Look 't be done.
+
+**@D|** I will, my lord.
+\lbracket|All but @D| and @E| exit.\rbracket|
+
+**@E|**
+How goes it now? He looks gentler than he did.
+
+**@D|**
+He says he will return incontinent,
+And hath commanded me to go to bed,
+And bade me to dismiss you.
+
+**@E|** Dismiss me?
+
+**@D|**
+It was his bidding. Therefore, good @E|,
+Give me my nightly wearing, and adieu.
+We must not now displease him.
+
+**@E|** I would you had never seen him.
+
+**@D|**
+So would not I. My love doth so approve him
+That even his stubbornness, his checks, his frowns--
+Prithee, unpin me--have grace and favor in them.
+
+**@E|**
+I have laid those sheets you bade me on the bed.
+
+**@D|**
+All's one. Good faith, how foolish are our minds!
+If I do die before thee, prithee, shroud me
+In one of those same sheets.
+
+**@E|** Come, come, you talk!
+
+**@D|**
+My mother had a maid called Barbary.
+She was in love, and he she loved proved mad
+And did forsake her. She had a song of willow,
+An old thing 'twas, but it expressed her fortune,
+And she died singing it. That song tonight
+Will not go from my mind. I have much to do
+But to go hang my head all at one side
+And sing it like poor Barbary. Prithee, dispatch.
+
+**@E|** Shall I go fetch your nightgown?
+
+**@D|** No, unpin me here.
+This @L| is a proper man.
+
+**@E|** A very handsome man.
+
+**@D|** He speaks well.
+
+**@E|** I know a lady in Venice would have walked
+barefoot to Palestine for a touch of his nether lip.
+
+**@D|**, \lbracket|singing\rbracket|
+ The poor soul sat sighing by a sycamore tree,
+ Sing all a green willow.
+ Her hand on her bosom, her head on her knee,
+ Sing willow, willow, willow.
+ The fresh streams ran by her and murmured her
+moans,
+ Sing willow, willow, willow\semicolon|
+ Her salt tears fell from her, and softened the
+stones--
+Lay by these.
+ Sing willow, willow, willow.
+Prithee hie thee! He'll come anon.
+ Sing all a green willow must be my garland.
+ Let nobody blame him, his scorn I approve.
+Nay, that's not next. Hark, who is 't that knocks?
+
+**@E|** It's the wind.
+
+**@D|**
+ I called my love false love, but what said he then?
+ Sing willow, willow, willow.
+ If I court more women, you'll couch with more
+men.--
+So, get thee gone. Good night. Mine eyes do itch\semicolon|
+Doth that bode weeping?
+
+**@E|** 'Tis neither here nor there.
+
+**@D|**
+I have heard it said so. O these men, these men!
+Dost thou in conscience think--tell me, @E|--
+That there be women do abuse their husbands
+In such gross kind?
+
+**@E|** There be some such, no
+question.
+
+**@D|**
+Wouldst thou do such a deed for all the world?
+
+**@E|**
+Why, would not you?
+
+**@D|** No, by this heavenly light!
+
+**@E|**
+Nor I neither, by this heavenly light.
+I might do 't as well i' th' dark.
+
+**@D|**
+Wouldst thou do such a deed for all the world?
+
+**@E|** The world's a huge thing. It is a great price
+for a small vice.
+
+**@D|** In troth, I think thou wouldst not.
+
+**@E|** In troth, I think I should, and undo 't when I
+had done it. Marry, I would not do such a thing for
+a joint ring, nor for measures of lawn, nor for
+gowns, petticoats, nor caps, nor any petty exhibition.
+But for the whole world--'Uds pity! Who
+would not make her husband a cuckold to make
+him a monarch? I should venture purgatory for 't.
+
+**@D|** Beshrew me if I would do such a wrong
+for the whole world!
+
+**@E|** Why, the wrong is but a wrong i' th' world\semicolon|
+and, having the world for your labor, 'tis a wrong in
+your own world, and you might quickly make it
+right.
+
+**@D|** I do not think there is any such woman.
+
+**@E|** Yes, a dozen\semicolon| and as many to th' vantage as
+would store the world they played for.
+But I do think it is their husbands' faults
+If wives do fall. Say that they slack their duties,
+And pour our treasures into foreign laps\semicolon|
+Or else break out in peevish jealousies,
+Throwing restraint upon us. Or say they strike us,
+Or scant our former having in despite.
+Why, we have galls, and though we have some grace,
+Yet have we some revenge. Let husbands know
+Their wives have sense like them. They see, and
+smell,
+And have their palates both for sweet and sour,
+As husbands have. What is it that they do
+When they change us for others? Is it sport?
+I think it is. And doth affection breed it?
+I think it doth. Is 't frailty that thus errs?
+It is so too. And have not we affections,
+Desires for sport, and frailty, as men have?
+Then let them use us well. Else let them know,
+The ills we do, their ills instruct us so.
+
+**@D|**
+Good night, good night. God me such uses send,
+Not to pick bad from bad, but by bad mend.
+\lbracket|They exit.\rbracket|
+
+\h1[Act 5]
+
+\h2[Scene 1]
+
+\lbracket|Enter @I| and @R|.\rbracket|
+
+
+**@I|**
+Here, stand behind this bulk. Straight will he
+come.
+Wear thy good rapier bare, and put it home.
+Quick, quick! Fear nothing. I'll be at thy elbow.
+It makes us or it mars us--think on that,
+And fix most firm thy resolution.
+
+**@R|**
+Be near at hand. I may miscarry in 't.
+
+**@I|**
+Here, at thy hand. Be bold and take thy stand.
+\lbracket|He moves aside.\rbracket|
+
+**@R|**
+I have no great devotion to the deed,
+And yet he hath given me satisfying reasons.
+'Tis but a man gone. Forth, my sword! He dies.
+\lbracket|He draws his sword.\rbracket|
+
+**@I|**, \lbracket|aside\rbracket|
+I have rubbed this young quat almost to the sense,
+And he grows angry. Now, whether he kill @C|,
+Or @C| him, or each do kill the other,
+Every way makes my gain. Live @R|,
+He calls me to a restitution large
+Of gold and jewels that I bobbed from him
+As gifts to @D|.
+It must not be. If @C| do remain,
+He hath a daily beauty in his life
+That makes me ugly. And besides, the Moor
+May unfold me to him. There stand I in much peril.
+No, he must die. Be 't so. I hear him coming.
+
+\lbracket|Enter @C|.\rbracket|
+
+
+**@R|**
+I know his gait. 'Tis he!--Villain, thou diest!
+\lbracket|He thrusts at @C|.\rbracket|
+
+**@C|**
+That thrust had been mine enemy indeed
+But that my coat is better than thou know'st.
+I will make proof of thine.
+\lbracket|He draws, and stabs @R|.\rbracket|
+
+**@R|** O, I am slain!
+\lbracket|@R| falls.\rbracket|
+\lbracket|@I| stabs @C| in the leg, and exits.\rbracket|
+
+**@C|**
+I am maimed forever! Help, ho! Murder, murder!
+
+\lbracket|Enter @O|.\rbracket|
+
+
+**@O|**
+The voice of @C|! @I| keeps his word.
+
+**@R|** O, villain that I am!
+
+**@O|**, \lbracket|aside\rbracket| It is even so.
+
+**@C|** O, help ho! Light! A surgeon!
+
+**@O|**, \lbracket|aside\rbracket|
+'Tis he! O brave @I|, honest and just,
+That hast such noble sense of thy friend's wrong!
+Thou teachest me.--Minion, your dear lies dead,
+And your unblest fate hies. Strumpet, I come.
+Forth of my heart those charms, thine eyes, are
+blotted.
+Thy bed, lust-stained, shall with lust's blood be
+spotted. \lbracket|@O| exits.\rbracket|
+
+\lbracket|Enter @L| and @G|.\rbracket|
+
+
+**@C|**
+What ho! No watch? No passage? Murder, murder!
+
+**@G|**
+'Tis some mischance. The voice is very direful.
+
+**@C|** O, help!
+
+**@L|** Hark!
+
+**@R|** O wretched villain!
+
+**@L|**
+Two or three groan. 'Tis heavy night.
+These may be counterfeits. Let's think 't unsafe
+To come in to the cry without more help.
+
+**@R|**
+Nobody come? Then shall I bleed to death.
+
+\lbracket|Enter @I| with a light.\rbracket|
+
+
+**@L|** Hark!
+
+**@G|**
+Here's one comes in his shirt, with light and
+weapons.
+
+**@I|**
+Who's there? Whose noise is this that cries on
+murder?
+
+**@L|**
+We do not know.
+
+**@I|** Did not you hear a cry?
+
+**@C|**
+Here, here! For heaven's sake, help me!
+
+**@I|** What's the matter?
+
+**@G|**, \lbracket|to @L|\rbracket|
+This is @O|'s ancient, as I take it.
+
+**@L|**
+The same indeed, a very valiant fellow.
+
+**@I|**, \lbracket|to @C|\rbracket|
+What are you here that cry so grievously?
+
+**@C|**
+@I|? O, I am spoiled, undone by villains.
+Give me some help!
+
+**@I|**
+O me, lieutenant! What villains have done this?
+
+**@C|**
+I think that one of them is hereabout
+And cannot make away.
+
+**@I|** O treacherous villains!
+\lbracket|To @L| and @G|.\rbracket| What are you there?
+Come in, and give some help.
+
+**@R|** O, help me here!
+
+**@C|**
+That's one of them.
+
+**@I|**, \lbracket|to @R|\rbracket| O murd'rous slave! O villain!
+\lbracket|He stabs @R|.\rbracket|
+
+**@R|**
+O damned @I|! O inhuman dog!
+
+**@I|**
+Kill men i' th' dark?--Where be these bloody
+thieves?
+How silent is this town! Ho, murder, murder!--
+What may you be? Are you of good or evil?
+
+**@L|**
+As you shall prove us, praise us.
+
+**@I|** Signior @L|?
+
+**@L|** He, sir.
+
+**@I|**
+I cry you mercy. Here's @C| hurt by villains.
+
+**@G|** @C|?
+
+**@I|**
+How is 't, brother?
+
+**@C|** My leg is cut in two.
+
+**@I|** Marry, heaven forbid!
+Light, gentlemen. I'll bind it with my shirt.
+
+\lbracket|Enter @BI|.\rbracket|
+
+
+**@BI|**
+What is the matter, ho? Who is 't that cried?
+
+**@I|**
+Who is 't that cried?
+
+**@BI|** O, my dear @C|,
+My sweet @C|! O @C|, @C|, @C|!
+
+**@I|**
+O notable strumpet! @C|, may you suspect
+Who they should be that have thus mangled you?
+
+**@C|** No.
+
+**@G|**
+I am sorry to find you thus\semicolon| I have been to seek you.
+
+**@I|**
+Lend me a garter. So.--O for a chair
+To bear him easily hence!
+
+**@BI|**
+Alas, he faints. O, @C|, @C|, @C|!
+
+**@I|**
+Gentlemen all, I do suspect this trash
+To be a party in this injury.--
+Patience awhile, good @C|.--Come, come\semicolon|
+Lend me a light. \lbracket|Peering at @R|.\rbracket| Know we this
+face or no?
+Alas, my friend and my dear countryman
+@R|? No! Yes, sure. O heaven, @R|!
+
+**@G|** What, of Venice?
+
+**@I|** Even he, sir. Did you know him?
+
+**@G|** Know him? Ay.
+
+**@I|**
+Signior @G|? I cry your gentle pardon.
+These bloody accidents must excuse my manners
+That so neglected you.
+
+**@G|** I am glad to see you.
+
+**@I|**
+How do you, @C|?--O, a chair, a chair!
+
+**@G|** @R|?
+
+**@I|**
+He, he, 'tis he! \lbracket|A chair is brought in.\rbracket| O, that's well
+said\semicolon| the chair.--
+Some good man bear him carefully from hence.
+I'll fetch the General's surgeon.-- For you, mistress,
+Save you your labor.--He that lies slain here,
+@C|,
+Was my dear friend. What malice was between you?
+
+**@C|**
+None in the world. Nor do I know the man.
+
+**@I|**, \lbracket|to @BI|\rbracket|
+What, look you pale?--O, bear him out o' th' air.
+\lbracket|@C|, in the chair, and @R| are carried off.\rbracket|
+\lbracket|To @G| and @L|.\rbracket| Stay you, good
+gentlemen.--Look you pale, mistress?--
+Do you perceive the gastness of her eye?--
+Nay, if you stare, we shall hear more anon.--
+Behold her well. I pray you, look upon her.
+Do you see, gentlemen? Nay, guiltiness will speak
+Though tongues were out of use.
+
+\lbracket|Enter @E|.\rbracket|
+
+
+**@E|**
+Alas, what is the matter? What is the matter,
+husband?
+
+**@I|**
+@C| hath here been set on in the dark
+By @R| and fellows that are scaped.
+He's almost slain, and @R| dead.
+
+**@E|**
+Alas, good gentleman! Alas, good @C|!
+
+**@I|**
+This is the fruits of whoring. Prithee, @E|,
+Go know of @C| where he supped tonight.
+\lbracket|To @BI|.\rbracket| What, do you shake at that?
+
+**@BI|**
+He supped at my house, but I therefore shake not.
+
+**@I|**
+O, did he so? I charge you go with me.
+
+**@E|** O fie upon thee, strumpet!
+
+**@BI|**
+I am no strumpet, but of life as honest
+As you that thus abuse me.
+
+**@E|** As I? Faugh! Fie upon thee!
+
+**@I|**
+Kind gentlemen, let's go see poor @C| dressed.--
+Come, mistress, you must tell 's another tale.--
+@E|, run you to the citadel
+And tell my lord and lady what hath happed.--
+Will you go on afore? \lbracket|Aside.\rbracket| This is the night
+That either makes me or fordoes me quite.
+\lbracket|They exit in different directions.\rbracket|
+
+\h2[Scene 2]
+
+\lbracket|Enter @O| with a light, and @D| in her bed.\rbracket|
+
+
+**@O|**
+It is the cause, it is the cause, my soul.
+Let me not name it to you, you chaste stars.
+It is the cause. Yet I'll not shed her blood,
+Nor scar that whiter skin of hers than snow,
+And smooth as monumental alabaster.
+Yet she must die, else she'll betray more men.
+Put out the light, and then put out the light.
+If I quench thee, thou flaming minister,
+I can again thy former light restore
+Should I repent me. But once put out thy light,
+Thou cunning'st pattern of excelling nature,
+I know not where is that Promethean heat
+That can thy light relume. When I have plucked the
+rose,
+I cannot give it vital growth again.
+It needs must wither. I'll smell it on the tree.
+O balmy breath, that dost almost persuade
+Justice to break her sword! \lbracket|He kisses her.\rbracket| One
+more, one more.
+Be thus when thou art dead, and I will kill thee
+And love thee after. One more, and this the last.
+\lbracket|He kisses her.\rbracket|
+So sweet was ne'er so fatal. I must weep,
+But they are cruel tears. This sorrow's heavenly:
+It strikes where it doth love. She wakes.
+
+**@D|**
+Who's there? @O|?
+
+**@O|** Ay, @D|.
+
+**@D|** Will you come to bed, my lord?
+
+**@O|**
+Have you prayed tonight, Desdemon?
+
+**@D|** Ay, my lord.
+
+**@O|**
+If you bethink yourself of any crime
+Unreconciled as yet to heaven and grace,
+Solicit for it straight.
+
+**@D|** Alack, my lord,
+What may you mean by that?
+
+**@O|**
+Well, do it, and be brief. I will walk by.
+I would not kill thy unprepared spirit.
+No, heaven forfend! I would not kill thy soul.
+
+**@D|** Talk you of killing?
+
+**@O|**
+Ay, I do.
+
+**@D|** Then heaven have mercy on me.
+
+**@O|** Amen, with all my heart.
+
+**@D|**
+If you say so, I hope you will not kill me.
+
+**@O|** Humh.
+
+**@D|**
+And yet I fear you, for you're fatal then
+When your eyes roll so. Why I should fear I know
+not,
+Since guiltiness I know not, but yet I feel I fear.
+
+**@O|**
+Think on thy sins.
+
+**@D|** They are loves I bear to you.
+
+**@O|** Ay, and for that thou diest.
+
+**@D|**
+That death's unnatural that kills for loving.
+Alas, why gnaw you so your nether lip?
+Some bloody passion shakes your very frame.
+These are portents, but yet I hope, I hope
+They do not point on me.
+
+**@O|** Peace, and be still.
+
+**@D|**
+I will so. What's the matter?
+
+**@O|** That handkerchief
+Which I so loved, and gave thee, thou gav'st to
+@C|.
+
+**@D|**
+No, by my life and soul! Send for the man
+And ask him.
+
+**@O|**
+Sweet soul, take heed, take heed of perjury.
+Thou art on thy deathbed.
+
+**@D|**
+Ay, but not yet to die.
+
+**@O|** Yes, presently.
+Therefore confess thee freely of thy sin.
+For to deny each article with oath
+Cannot remove nor choke the strong conception
+That I do groan withal. Thou art to die.
+
+**@D|**
+Then Lord have mercy on me!
+
+**@O|** I say "Amen."
+
+**@D|**
+And have you mercy, too. I never did
+Offend you in my life, never loved @C|
+But with such general warranty of heaven
+As I might love. I never gave him token.
+
+**@O|**
+By heaven, I saw my handkerchief in 's hand!
+O perjured woman, thou dost stone my heart
+And mak'st me call what I intend to do
+A murder, which I thought a sacrifice!
+I saw the handkerchief!
+
+**@D|** He found it, then.
+I never gave it him. Send for him hither.
+Let him confess a truth.
+
+**@O|** He hath confessed.
+
+**@D|** What, my lord?
+
+**@O|**
+That he hath used thee.
+
+**@D|** How? Unlawfully?
+
+**@O|** Ay.
+
+**@D|**
+He will not say so.
+
+**@O|** No. His mouth is stopped.
+Honest @I| hath ta'en order for 't.
+
+**@D|**
+O, my fear interprets. What, is he dead?
+
+**@O|**
+Had all his hairs been lives, my great revenge
+Had stomach for them all.
+
+**@D|**
+Alas, he is betrayed, and I undone. \lbracket|She weeps.\rbracket|
+
+**@O|**
+Out, strumpet! Weep'st thou for him to my face?
+
+**@D|**
+O banish me, my lord, but kill me not!
+
+**@O|** Down, strumpet!
+
+**@D|**
+Kill me tomorrow, let me live tonight.
+
+**@O|** Nay, if you strive--
+
+**@D|**
+But half an hour!
+
+**@O|** Being done, there is no pause.
+
+**@D|**
+But while I say one prayer!
+
+**@O|** It is too late.
+\lbracket|He smothers her.\rbracket|
+
+**@E|**, \lbracket|within\rbracket|
+My lord, my lord? What ho! My lord, my lord!
+
+**@O|**
+What noise is this?--Not dead? Not yet quite dead?
+I that am cruel am yet merciful.
+I would not have thee linger in thy pain.
+So, so.
+
+**@E|**, \lbracket|within\rbracket| What, ho! My lord, my lord!
+
+**@O|** Who's
+there?
+
+**@E|**, \lbracket|within\rbracket|
+O, good my lord, I would speak a word with you.
+
+**@O|**
+Yes. 'Tis @E|.--By and by.--She's dead.
+'Tis like she comes to speak of @C|'s death.
+The noise was here. Ha, no more moving?
+Still as the grave. Shall she come in? Were 't good?
+I think she stirs again. No. What's best to do?
+If she come in, she'll sure speak to my wife.
+My wife, my wife! What wife? I have no wife.
+O insupportable! O heavy hour!
+Methinks it should be now a huge eclipse
+Of sun and moon, and that th' affrighted globe
+Should yawn at alteration.
+
+**@E|**, \lbracket|within\rbracket| I do beseech you
+That I may speak with you. O, good my lord--
+
+**@O|**
+I had forgot thee. O, come in, @E|.--
+Soft, by and by, let me the curtains draw.--
+Where art thou?
+
+\lbracket|Enter @E|.\rbracket|
+
+What's the matter with thee now?
+
+**@E|**
+O, my good lord, yonder's foul murders done.
+
+**@O|** What? Now?
+
+**@E|** But now, my lord.
+
+**@O|**
+It is the very error of the moon.
+She comes more nearer Earth than she was wont
+And makes men mad.
+
+**@E|** @C|, my lord, hath killed
+A young Venetian called @R|.
+
+**@O|**
+@R| killed? And @C| killed?
+
+**@E|** No, @C| is not killed.
+
+**@O|**
+Not @C| killed? Then murder's out of tune,
+And sweet revenge grows harsh.
+
+**@D|** O falsely, falsely murdered.
+
+**@E|**
+O Lord, what cry is that?
+
+**@O|** That? What?
+
+**@E|**
+Out, and alas, that was my lady's voice!
+Help! Help ho! Help! O lady, speak again!
+Sweet @D|, O sweet mistress, speak!
+
+**@D|** A guiltless death I die.
+
+**@E|** O, who hath done this deed?
+
+**@D|** Nobody. I myself. Farewell.
+Commend me to my kind lord. O, farewell.
+\lbracket|She dies.\rbracket|
+
+**@O|**
+Why, how should she be murdered?
+
+**@E|** Alas, who
+knows?
+
+**@O|**
+You heard her say herself, it was not I.
+
+**@E|**
+She said so. I must needs report the truth.
+
+**@O|**
+She's like a liar gone to burning hell!
+'Twas I that killed her.
+
+**@E|**
+O, the more angel she, and you the blacker devil!
+
+**@O|**
+She turned to folly, and she was a whore.
+
+**@E|**
+Thou dost belie her, and thou art a devil!
+
+**@O|** She was false as water.
+
+**@E|** Thou art rash as fire to say
+That she was false. O, she was heavenly true!
+
+**@O|**
+@C| did top her. Ask thy husband else.
+O, I were damned beneath all depth in hell
+But that I did proceed upon just grounds
+To this extremity. Thy husband knew it all.
+
+**@E|** My husband?
+
+**@O|** Thy husband.
+
+**@E|** That she was false to wedlock?
+
+**@O|**
+Ay, with @C|. Had she been true,
+If heaven would make me such another world
+Of one entire and perfect chrysolite,
+I'd not have sold her for it.
+
+**@E|** My husband?
+
+**@O|**
+Ay, 'twas he that told me on her first.
+An honest man he is, and hates the slime
+That sticks on filthy deeds.
+
+**@E|** My husband?
+
+**@O|**
+What needs this iterance, woman? I say, thy
+husband.
+
+**@E|**
+O mistress, villainy hath made mocks with love!--
+My husband say she was false?
+
+**@O|** He, woman.
+I say thy husband. Dost understand the word?
+My friend, thy husband\semicolon| honest, honest @I|.
+
+**@E|**
+If he say so, may his pernicious soul
+Rot half a grain a day! He lies to th' heart!
+She was too fond of her most filthy bargain.
+\lbracket|He draws his sword.\rbracket|
+
+**@O|** Hah?
+
+**@E|** Do thy worst!
+This deed of thine is no more worthy heaven
+Than thou wast worthy her.
+
+**@O|** Peace, you were best!
+
+**@E|**
+Thou hast not half that power to do me harm
+As I have to be hurt. O gull! O dolt,
+As ignorant as dirt! Thou hast done a deed--
+I care not for thy sword. I'll make thee known,
+Though I lost twenty lives. Help! Help, ho! Help!
+The Moor hath killed my mistress! Murder, murder!
+
+\lbracket|Enter @M|, @G|, and @I|.\rbracket|
+
+
+**@M|**
+What is the matter? How now, general?
+
+**@E|**
+O, are you come, @I|? You have done well,
+That men must lay their murders on your neck.
+
+**@G|** What is the matter?
+
+**@E|**, \lbracket|to @I|\rbracket|
+Disprove this villain, if thou be'st a man.
+He says thou told'st him that his wife was false.
+I know thou didst not. Thou 'rt not such a villain.
+Speak, for my heart is full.
+
+**@I|**
+I told him what I thought, and told no more
+Than what he found himself was apt and true.
+
+**@E|**
+But did you ever tell him she was false?
+
+**@I|** I did.
+
+**@E|**
+You told a lie, an odious, damned lie!
+Upon my soul, a lie, a wicked lie!
+She false with @C|? Did you say with @C|?
+
+**@I|**
+With @C|, mistress. Go to! Charm your tongue.
+
+**@E|**
+I will not charm my tongue. I am bound to speak.
+My mistress here lies murdered in her bed.
+
+**ALL** O heavens forfend!
+
+**@E|**, \lbracket|to @I|\rbracket|
+And your reports have set the murder on!
+
+**@O|**
+Nay, stare not, masters\semicolon| it is true indeed.
+
+**@G|** 'Tis a strange truth.
+
+**@M|**
+O monstrous act!
+
+**@E|** Villainy, villainy, villainy!
+I think upon 't, I think! I smell 't! O villainy!
+I thought so then. I'll kill myself for grief!
+O villainy! Villainy!
+
+**@I|**
+What, are you mad? I charge you get you home.
+
+**@E|**
+Good gentlemen, let me have leave to speak.
+'Tis proper I obey him, but not now.
+Perchance, @I|, I will ne'er go home.
+
+**@O|**
+O, O, O! \lbracket|@O| falls on the bed.\rbracket|
+
+**@E|** Nay, lay thee down, and roar!
+For thou hast killed the sweetest innocent
+That e'er did lift up eye.
+
+**@O|**, \lbracket|standing\rbracket| O, she was foul!--
+I scarce did know you, uncle. There lies your niece,
+Whose breath indeed these hands have newly
+stopped.
+I know this act shows horrible and grim.
+
+**@G|**
+Poor Desdemon, I am glad thy father's dead.
+Thy match was mortal to him, and pure grief
+Shore his old thread in twain. Did he live now,
+This sight would make him do a desperate turn,
+Yea, curse his better angel from his side,
+And fall to reprobance.
+
+**@O|**
+'Tis pitiful. But yet @I| knows
+That she with @C| hath the act of shame
+A thousand times committed. @C| confessed it,
+And she did gratify his amorous works
+With that recognizance and pledge of love
+Which I first gave her. I saw it in his hand.
+It was a handkerchief, an antique token
+My father gave my mother.
+
+**@E|** O God! O heavenly God!
+
+**@I|**
+Zounds, hold your peace!
+
+**@E|** 'Twill out, 'twill out. I peace?
+No, I will speak as liberal as the north.
+Let heaven and men and devils, let them all,
+All, all, cry shame against me, yet I'll speak.
+
+**@I|** Be wise, and get you home.
+\lbracket|He draws his sword.\rbracket|
+
+**@E|**
+I will not.
+
+**@G|** Fie, your sword upon a woman!
+
+**@E|**
+O thou dull Moor, that handkerchief thou speak'st
+of
+I found by fortune, and did give my husband--
+For often, with a solemn earnestness
+(More than indeed belonged to such a trifle),
+He begged of me to steal 't.
+
+**@I|** Villainous whore!
+
+**@E|**
+She give it @C|? No, alas, I found it,
+And I did give 't my husband.
+
+**@I|** Filth, thou liest!
+
+**@E|**
+By heaven, I do not, I do not, gentlemen!
+\lbracket|To @O|.\rbracket| O murd'rous coxcomb, what should
+such a fool
+Do with so good a wife?
+
+**@O|** Are there no stones in heaven
+But what serves for the thunder?--Precious villain!
+\lbracket|The Moor runs at @I| but is disarmed.\rbracket|
+\lbracket|@I| kills his wife.\rbracket|
+
+**@G|**
+The woman falls! Sure he hath killed his wife.
+
+**@E|**
+Ay, ay! O, lay me by my mistress' side. \lbracket|@I| exits.\rbracket|
+
+**@G|** He's gone, but his wife's killed.
+
+**@M|**
+'Tis a notorious villain. Take you this weapon
+Which I have here recovered from the Moor.
+Come, guard the door without. Let him not pass,
+But kill him rather. I'll after that same villain,
+For 'tis a damned slave.
+\lbracket|@M| and @G| exit.\rbracket|
+
+**@O|** I am not valiant neither,
+But every puny whipster gets my sword.
+But why should honor outlive honesty?
+Let it go all.
+
+**@E|** What did thy song bode, lady?
+Hark, canst thou hear me? I will play the swan
+And die in music.
+\lbracket|She sings.\rbracket| Willow, willow, willow.
+Moor, she was chaste. She loved thee, cruel Moor.
+So come my soul to bliss, as I speak true.
+So speaking as I think, alas, I die. \lbracket|She dies.\rbracket|
+
+**@O|**
+I have another weapon in this chamber.
+It is a sword of Spain, the ice brook's temper.
+O, here it is.--Uncle, I must come forth.
+
+**@G|**, \lbracket|within\rbracket|
+If thou attempt it, it will cost thee dear\semicolon|
+Thou hast no weapon and perforce must suffer.
+
+**@O|**
+Look in upon me, then, and speak with me,
+Or naked as I am I will assault thee.
+
+\lbracket|Enter @G|.\rbracket|
+
+
+**@G|**
+What is the matter?
+
+**@O|** Behold, I have a weapon.
+A better never did itself sustain
+Upon a soldier's thigh. I have seen the day
+That with this little arm and this good sword
+I have made my way through more impediments
+Than twenty times your stop. But--O vain boast!--
+Who can control his fate? 'Tis not so now.
+Be not afraid, though you do see me weaponed.
+Here is my journey's end, here is my butt
+And very sea-mark of my utmost sail.
+Do you go back dismayed? 'Tis a lost fear.
+Man but a rush against @O|'s breast,
+And he retires. Where should @O| go?
+\lbracket|He looks toward the bed.\rbracket|
+Now, how dost thou look now? O ill-starred wench,
+Pale as thy smock, when we shall meet at compt,
+This look of thine will hurl my soul from heaven,
+And fiends will snatch at it. Cold, cold, my girl?
+Even like thy chastity.--O cursed, cursed slave!--
+Whip me, you devils,
+From the possession of this heavenly sight!
+Blow me about in winds, roast me in sulfur,
+Wash me in steep-down gulfs of liquid fire!
+O Desdemon! Dead, Desdemon! Dead! O, O!
+
+ \lbracket|Enter @L|, @C| in a chair, @M|, and @I|,
+with Officers.\rbracket|
+
+
+**@L|**
+Where is this rash and most unfortunate man?
+
+**@O|**
+That's he that was @O|. Here I am.
+
+**@L|**
+Where is that viper? Bring the villain forth.
+\lbracket|@I| is brought forward.\rbracket|
+
+**@O|**
+I look down towards his feet\semicolon| but that's a fable.--
+If that thou be'st a devil, I cannot kill thee.
+\lbracket|He stabs @I|.\rbracket|
+
+**@L|**
+Wrench his sword from him.
+\lbracket|@O| is disarmed.\rbracket|
+
+**@I|** I bleed, sir, but not killed.
+
+**@O|**
+I am not sorry neither. I'd have thee live,
+For in my sense 'tis happiness to die.
+
+**@L|**
+O thou @O|, that wert once so good,
+Fall'n in the practice of a damned slave,
+What shall be said to thee?
+
+**@O|** Why, anything.
+An honorable murderer, if you will,
+For naught I did in hate, but all in honor.
+
+**@L|**
+This wretch hath part confessed his villainy.
+Did you and he consent in @C|'s death?
+
+**@O|** Ay.
+
+**@C|**
+Dear general, I never gave you cause.
+
+**@O|**
+I do believe it, and I ask your pardon.
+Will you, I pray, demand that demi-devil
+Why he hath thus ensnared my soul and body?
+
+**@I|**
+Demand me nothing. What you know, you know.
+From this time forth I never will speak word.
+
+**@L|** What? Not to pray?
+
+**@G|** Torments will ope your lips.
+
+**@O|** Well, thou dost best.
+
+**@L|** Sir,
+You shall understand what hath befall'n,
+Which, as I think, you know not. Here is a letter
+Found in the pocket of the slain @R|,
+And here another. \lbracket|He shows papers.\rbracket| The one of
+them imports
+The death of @C|, to be undertook
+By @R|.
+
+**@O|**
+O villain!
+
+**@C|** Most heathenish and most gross.
+
+**@L|**
+Now here's another discontented paper
+Found in his pocket, too\semicolon| and this it seems
+@R| meant t' have sent this damned villain,
+But that, belike, @I| in the interim
+Came in and satisfied him.
+
+**@O|** O, thou pernicious caitiff!--
+How came you, @C|, by that handkerchief
+That was my wife's?
+
+**@C|** I found it in my chamber.
+And he himself confessed it but even now,
+That there he dropped it for a special purpose
+Which wrought to his desire.
+
+**@O|** O fool, fool, fool!
+
+**@C|**
+There is besides, in @R|'s letter,
+How he upbraids @I|, that he made him
+Brave me upon the watch, whereon it came
+That I was cast. And even but now he spake,
+After long seeming dead: @I| hurt him,
+@I| set him on.
+
+**@L|**, \lbracket|to @O|\rbracket|
+You must forsake this room and go with us.
+Your power and your command is taken off,
+And @C| rules in Cyprus. For this slave,
+If there be any cunning cruelty
+That can torment him much and hold him long,
+It shall be his. You shall close prisoner rest,
+Till that the nature of your fault be known
+To the Venetian state.--Come, bring away.
+
+**@O|**
+Soft you. A word or two before you go.
+I have done the state some service, and they
+know 't.
+No more of that. I pray you in your letters,
+When you shall these unlucky deeds relate,
+Speak of me as I am. Nothing extenuate,
+Nor set down aught in malice. Then must you speak
+Of one that loved not wisely, but too well\semicolon|
+Of one not easily jealous, but being wrought,
+Perplexed in the extreme\semicolon| of one whose hand,
+Like the base Judean, threw a pearl away
+Richer than all his tribe\semicolon| of one whose subdued
+eyes,
+Albeit unused to the melting mood,
+Drops tears as fast as the Arabian trees
+Their medicinable gum. Set you down this.
+And say besides, that in Aleppo once,
+Where a malignant and a turbanned Turk
+Beat a Venetian and traduced the state,
+I took by th' throat the circumcised dog,
+And smote him, thus. \lbracket|He stabs himself.\rbracket|
+
+**@L|** O bloody period!
+
+**@G|** All that is spoke is marred.
+
+**@O|**, \lbracket|to @D|\rbracket|
+I kissed thee ere I killed thee. No way but this,
+Killing myself, to die upon a kiss. \lbracket|He dies.\rbracket|
+
+**@C|**
+This did I fear, but thought he had no weapon,
+For he was great of heart.
+
+**@L|**, \lbracket|to @I|\rbracket| O Spartan dog,
+More fell than anguish, hunger, or the sea,
+Look on the tragic loading of this bed.
+This is thy work.--The object poisons sight.
+Let it be hid.--@G|, keep the house,
+And seize upon the fortunes of the Moor,
+For they succeed on you. \lbracket|To @C|.\rbracket| To you, lord
+governor,
+Remains the censure of this hellish villain.
+The time, the place, the torture, O, enforce it.
+Myself will straight aboard, and to the state
+This heavy act with heavy heart relate.
+\lbracket|They exit.\rbracket|
diff --git a/doc/project_mockup/src/dictionary.zoia b/doc/project_mockup/src/dictionary.zoia
index c2e64c5..c1e003b 100644
--- a/doc/project_mockup/src/dictionary.zoia
+++ b/doc/project_mockup/src/dictionary.zoia
@@ -1,3 +1,3 @@
-\header[dict]
+\header[dictionary]
\dict_add[Hugglesworth]
diff --git a/grammar/zoia.g4 b/grammar/zoia.g4
index 61cd0ff..b036c20 100644
--- a/grammar/zoia.g4
+++ b/grammar/zoia.g4
@@ -25,8 +25,16 @@ header: Header arguments Newline;
line: lineElements? Newline;
lineElements: (textFragment | alias | command | em1LineElement |
em2LineElement | em3LineElement)+;
-// The lineElements that may occur inside emLineElements
+// The lineElements that may occur inside em*LineElements
+// This prevents nested em*LineElements
lineElementsInner: (textFragmentReq | alias | command)+;
+// The lineElements that may occur inside *Arguments
+// This resolves an ambiguity/context sensitivity by requiring that
+// the first text fragment not start with spaces.
+lineElementsArg: (textFragmentWord | alias | command |
+ em1LineElement | em2LineElement | em3LineElement)
+ (textFragment | alias | command |
+ em1LineElement | em2LineElement | em3LineElement)*;
// One or more line elements, surrounded by 1-3 asterisks.
em3LineElement: Asterisk Asterisk Asterisk
@@ -39,6 +47,8 @@ em1LineElement: Asterisk lineElementsInner Asterisk;
textFragment: Word | Spaces;
// Version of textFragment that may not evaluate to pure whitespace.
textFragmentReq: Spaces? Word Spaces?;
+// Version of textFragmentReq that must begin with a word.
+textFragmentWord: Word Spaces?;
// An at sign followed by a word. May optionally be ended by a
// vertical bar (this is necessary when an alias is followed by
@@ -64,8 +74,8 @@ arguments: BracketsOpen whitespace? argument
// Either a text fragment or a word, an equals sign and a text
// fragment.
argument: kwdArgument | stdArgument;
-kwdArgument: Word Spaces? Equals Spaces? lineElements;
-stdArgument: lineElements;
+kwdArgument: Word Spaces? Equals Spaces? lineElementsArg;
+stdArgument: lineElementsArg;
// Any kind of whitespace: newlines, spaces, tabs, etc.
whitespace: (Newline | Spaces)+;
diff --git a/setup.py b/setup.py
index 75a91fe..d063d13 100644
--- a/setup.py
+++ b/setup.py
@@ -19,9 +19,9 @@ def run_setup(with_binary):
extra_compile_args = {
'windows': ['/DANTLR4CPP_STATIC', '/Zc:__cplusplus'],
- 'linux': ['-std=c++11'],
- 'darwin': ['-std=c++11'],
- 'cygwin': ['-std=c++11'],
+ 'linux': ['-std=c++11', '-g0'],
+ 'darwin': ['-std=c++11', '-g0'],
+ 'cygwin': ['-std=c++11', '-g0'],
}
# Define an Extension object that describes the Antlr accelerator
diff --git a/src/ast_nodes/base.py b/src/ast_nodes/base.py
index 91c2e4a..396d9d4 100644
--- a/src/ast_nodes/base.py
+++ b/src/ast_nodes/base.py
@@ -29,17 +29,17 @@
@dataclass(slots=True)
class AASTNode:
"""Base class for all Zoia AST nodes."""
- src_pos: SourcePos = field(kw_only=True)
+ src_pos: SourcePos = field(kw_only=True, repr=False)
def accept(self, visitor):
"""Called by a visitor when it's about to visit this node. It should
call a specific method on the visitor that will then visit this
node."""
- raise AbstractError(self.accept)
+ raise AbstractError()
def canonical(self) -> str:
"""Returns a canonical string representation of this node."""
- raise AbstractError(self.canonical)
+ raise AbstractError()
def _write_arguments(s: StringIO, arguments: list[AASTNode]) -> None:
"""Helper method for writing out a list of nodes as arguments to a
@@ -47,11 +47,15 @@ def _write_arguments(s: StringIO, arguments: list[AASTNode]) -> None:
vertical bar as a terminator, if the command does not have any
arguments)."""
if arguments:
- s.write('[\n')
- for a in arguments:
- s.write(' ')
- s.write(a.canonical())
- s.write(';\n')
+ s.write('[')
+ if len(arguments) == 1:
+ s.write(arguments[0].canonical())
+ else:
+ s.write('\n')
+ for a in arguments:
+ s.write(' ')
+ s.write(a.canonical())
+ s.write(';\n')
s.write(']')
else:
s.write('|')
diff --git a/src/ast_nodes/em1_line_element.py b/src/ast_nodes/em1_line_element.py
index 9ee6fea..ceaca46 100644
--- a/src/ast_nodes/em1_line_element.py
+++ b/src/ast_nodes/em1_line_element.py
@@ -27,7 +27,6 @@
@dataclass(slots=True)
class Em1LineElementNode(AEmLineElementNode):
"""AST node for level 1 emphasized line elements."""
-
def accept(self, visitor):
return visitor.visit_em1_line_element(self)
diff --git a/src/ast_nodes/em2_line_element.py b/src/ast_nodes/em2_line_element.py
index 251dfec..9352ddf 100644
--- a/src/ast_nodes/em2_line_element.py
+++ b/src/ast_nodes/em2_line_element.py
@@ -27,7 +27,6 @@
@dataclass(slots=True)
class Em2LineElementNode(AEmLineElementNode):
"""AST node for level 2 emphasized line elements."""
-
def accept(self, visitor):
return visitor.visit_em2_line_element(self)
diff --git a/src/ast_nodes/em3_line_element.py b/src/ast_nodes/em3_line_element.py
index ea0c87c..79acd67 100644
--- a/src/ast_nodes/em3_line_element.py
+++ b/src/ast_nodes/em3_line_element.py
@@ -27,7 +27,6 @@
@dataclass(slots=True)
class Em3LineElementNode(AEmLineElementNode):
"""AST node for level 3 emphasized line elements."""
-
def accept(self, visitor):
return visitor.visit_em3_line_element(self)
diff --git a/src/ast_nodes/header.py b/src/ast_nodes/header.py
index 65ad4c8..dccc610 100644
--- a/src/ast_nodes/header.py
+++ b/src/ast_nodes/header.py
@@ -20,7 +20,7 @@
#
# =============================================================================
"""Implements the AST node for headers."""
-from dataclasses import dataclass
+from dataclasses import dataclass, field
from io import StringIO
from ast_nodes.argument import AArgumentNode
@@ -30,6 +30,8 @@
class HeaderNode(AASTNode):
"""AST node for file headers."""
arguments: list[AArgumentNode]
+ # Set by ASTValidator
+ header_type: str = field(init=False)
def accept(self, visitor):
return visitor.visit_header(self)
diff --git a/src/ast_nodes/std_argument.py b/src/ast_nodes/std_argument.py
index 1089816..d955bfc 100644
--- a/src/ast_nodes/std_argument.py
+++ b/src/ast_nodes/std_argument.py
@@ -27,6 +27,5 @@
@dataclass(slots=True)
class StdArgumentNode(AArgumentNode):
"""AST node for standard arguments."""
-
def accept(self, visitor):
return visitor.visit_std_argument(self)
diff --git a/src/ast_validator.py b/src/ast_validator.py
new file mode 100644
index 0000000..599276b
--- /dev/null
+++ b/src/ast_validator.py
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""Performs validation on a parsed Zoia AST."""
+from ast_nodes import ZoiaFileNode, HeaderNode, StdArgumentNode, LineNode, \
+ LineElementsNode, Em1LineElementNode, Em2LineElementNode, \
+ Em3LineElementNode, TextFragmentNode, AliasNode, CommandNode, \
+ KwdArgumentNode
+from ast_visitor import AASTVisitor
+from exception import ValidationError
+
+class ASTValidator(AASTVisitor):
+ """Performs validation on a Zoia AST, detecting and reporting errors that
+ cannot be detected during parsing."""
+ def visit_zoia_file(self, node: ZoiaFileNode):
+ self.visit_header(node.header)
+ for l in node.lines:
+ self.visit_line(l)
+
+ # TODO We're going to have to turn this into a more general system if we
+ # want to validate arbitrary commands - some sort of signature class?
+ def visit_header(self, node: HeaderNode):
+ # TODO Do we have a use case for >1 argument passed to the header? If
+ # not, add a check here for != 1
+ # The grammar guarantees that we have at least one argument
+ if not isinstance(node.arguments[0], StdArgumentNode):
+ raise ValidationError(
+ node.arguments[0].src_pos,
+ 'The first argument passed to \\header must be a standard '
+ 'argument')
+ arg_elements = node.arguments[0].arg_value.elements
+ txt_frag_msg = ('The first argument passed to \\header must be a '
+ 'single text fragment containing one word')
+ if len(arg_elements) > 1:
+ raise ValidationError(arg_elements[1].src_pos, txt_frag_msg)
+ txt_frag = arg_elements[0]
+ if not isinstance(txt_frag, TextFragmentNode):
+ raise ValidationError(txt_frag.src_pos, txt_frag_msg)
+ # Strip the text value to be forgiving of trailing whitespace
+ txt_frag_val = txt_frag.text_val.strip()
+ # TODO This should check that the header type argument is recognized
+ node.header_type = txt_frag_val
+ for a in node.arguments:
+ self.visit(a)
+
+ def visit_line(self, node: LineNode):
+ if n_elements := node.elements:
+ self.visit_line_elements(n_elements)
+
+ def visit_line_elements(self, node: LineElementsNode):
+ for e in node.elements:
+ self.visit(e)
+
+ def visit_em1_line_element(self, node: Em1LineElementNode):
+ self.visit_line_elements(node.elements)
+
+ def visit_em2_line_element(self, node: Em2LineElementNode):
+ self.visit_line_elements(node.elements)
+
+ def visit_em3_line_element(self, node: Em3LineElementNode):
+ self.visit_line_elements(node.elements)
+
+ def visit_text_fragment(self, node: TextFragmentNode):
+ pass
+
+ def visit_alias(self, node: AliasNode):
+ pass
+
+ def visit_command(self, node: CommandNode):
+ # TODO This should check that the command exists and that the arguments
+ # passed to it are OK
+ for a in node.arguments:
+ self.visit(a)
+
+ def visit_kwd_argument(self, node: KwdArgumentNode):
+ self.visit_line_elements(node.arg_value)
+
+ def visit_std_argument(self, node: StdArgumentNode):
+ self.visit_line_elements(node.arg_value)
diff --git a/src/build_backend/__init__.py b/src/build_backend/__init__.py
new file mode 100644
index 0000000..b3aad06
--- /dev/null
+++ b/src/build_backend/__init__.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""This package implements various backends for the build process. They are
+responsible for turning the AST into one or more files as output - e.g. the
+plaintext backend (`plain`) will output UTF-8 plaintext files containing the
+built story.
+
+All imports should come directly from here - *never* import from the actual
+files that define the classes. That way they can be moved around easily."""
diff --git a/src/build_backend/ao3/__init__.py b/src/build_backend/ao3/__init__.py
new file mode 100644
index 0000000..aef564d
--- /dev/null
+++ b/src/build_backend/ao3/__init__.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""This package implements the AO3 (Archive Of Our Own) backend.
+
+All imports should come directly from here - *never* import from the actual
+files that define the classes. That way they can be moved around easily."""
diff --git a/src/build_backend/html/__init__.py b/src/build_backend/html/__init__.py
new file mode 100644
index 0000000..384fd73
--- /dev/null
+++ b/src/build_backend/html/__init__.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""This package implements the HTML backend.
+
+All imports should come directly from here - *never* import from the actual
+files that define the classes. That way they can be moved around easily."""
diff --git a/src/build_backend/plain/__init__.py b/src/build_backend/plain/__init__.py
new file mode 100644
index 0000000..e94ebd3
--- /dev/null
+++ b/src/build_backend/plain/__init__.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""This package implements the plaintext backend.
+
+All imports should come directly from here - *never* import from the actual
+files that define the classes. That way they can be moved around easily."""
diff --git a/src/build_shared/__init__.py b/src/build_shared/__init__.py
new file mode 100644
index 0000000..a59cd8a
--- /dev/null
+++ b/src/build_shared/__init__.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""This package implements the parts of the build process that are identical in
+every backend, e.g. alias resolution.
+
+All imports should come directly from here - *never* import from the actual
+files that define the classes. That way they can be moved around easily."""
+from build_shared.aliases_eval import *
diff --git a/src/build_shared/aliases_eval.py b/src/build_shared/aliases_eval.py
new file mode 100644
index 0000000..c06e36d
--- /dev/null
+++ b/src/build_shared/aliases_eval.py
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""Implements evaluation of Zoia file of type 'aliases' (also named
+'aliases.zoia' by default)."""
+from ast_nodes import AASTNode, ZoiaFileNode, HeaderNode, LineNode, \
+ LineElementsNode, CommandNode, StdArgumentNode, TextFragmentNode
+from ast_visitor import AASTVisitor
+from exception import EvalError
+
+class AliasesEvaluator(AASTVisitor):
+ r"""Evaluates an aliases file to resolve all \def_alias commands in it and
+ return them in the form of an easy to process dict."""
+ # Override to add return value type
+ def visit(self, tree: AASTNode) -> dict[str, LineElementsNode]:
+ # pylint: disable=useless-super-delegation
+ return super().visit(tree)
+
+ def _visit_default(self, node: AASTNode):
+ raise EvalError(
+ node.src_pos,
+ f"Unexpected node of type {node.__class__.__name__} in an aliases "
+ f"file. Only \\def_alias commands are allowed")
+
+ def visit_zoia_file(self, node: ZoiaFileNode) \
+ -> dict[str, LineElementsNode]:
+ self.visit_header(node.header)
+ final_aliases = []
+ extend_aliases = final_aliases.extend
+ visit_ln = self.visit_line
+ for l in node.lines:
+ extend_aliases(visit_ln(l))
+ ret_dict = {}
+ seen_alias_keys = set()
+ add_alias_key = seen_alias_keys.add
+ for alias_frag, alias_val in final_aliases:
+ # Be forgiving of extra whitespace
+ alias_key = alias_frag.text_val.strip()
+ if alias_key in seen_alias_keys:
+ raise EvalError(
+ alias_frag.src_pos,
+ f"Duplicate alias key '{alias_key}'")
+ else:
+ add_alias_key(alias_key)
+ ret_dict[alias_key] = alias_val
+ return ret_dict
+
+ def visit_header(self, node: HeaderNode):
+ if node.header_type != 'aliases':
+ raise EvalError(
+ node.arguments[0].arg_value.elements[0].src_pos,
+ f"Aliases files must have header type 'aliases', but had "
+ f"header type '{node.header_type}' instead")
+
+ def visit_line(self, node: LineNode) \
+ -> list[tuple[TextFragmentNode, LineElementsNode]]:
+ if n_elements := node.elements:
+ return self.visit_line_elements(n_elements)
+ return []
+
+ def visit_line_elements(self, node: LineElementsNode) \
+ -> list[tuple[TextFragmentNode, LineElementsNode]]:
+ ret_aliases = []
+ append_alias = ret_aliases.append
+ visit_cmd = self.visit_command
+ for line_el in node.elements:
+ if isinstance(line_el, CommandNode):
+ append_alias(visit_cmd(line_el))
+ else:
+ # Only \def_alias commands are OK, raise an error
+ self._visit_default(line_el)
+ return ret_aliases
+
+ def visit_command(self, node: CommandNode) \
+ -> tuple[TextFragmentNode, LineElementsNode]:
+ if node.cmd_name != 'def_alias':
+ raise EvalError(
+ node.src_pos,
+ f"Unexpected '\\{node.cmd_name}' command in an aliases file. "
+ f"Only \\def_alias commands are allowed")
+ # TODO This is validation, it should be in ASTValidator (note how
+ # similar it is!). See TODOs there though
+ std_arg_msg = ('Invalid \\def_alias command: Exactly two standard '
+ 'arguments are required')
+ if len(node.arguments) != 2:
+ raise EvalError(node.src_pos, std_arg_msg)
+ if any(not isinstance(a, StdArgumentNode) for a in node.arguments):
+ raise EvalError(node.src_pos, std_arg_msg)
+ txt_frag_msg = ('The first argument passed to \\def_alias must be a '
+ 'single text fragment containing one word')
+ arg_elements = node.arguments[0].arg_value.elements
+ if len(arg_elements) > 1:
+ raise EvalError(arg_elements[1].src_pos, txt_frag_msg)
+ txt_frag = arg_elements[0]
+ if not isinstance(txt_frag, TextFragmentNode):
+ raise EvalError(txt_frag.src_pos, txt_frag_msg)
+ return txt_frag, node.arguments[1].arg_value
diff --git a/src/build_supervisor.py b/src/build_supervisor.py
new file mode 100644
index 0000000..68bf5c4
--- /dev/null
+++ b/src/build_supervisor.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""This module supervises the entire build process by launching the various
+shared and backend tasks."""
+from build_shared import AliasesEvaluator
+from project import Project
+
+def build(project: Project):
+ """Begins building the specified project based on its config."""
+ # Stage 1: Evaluating the aliases.zoia file
+ als_tree = project.aliases_file.file_ast
+ als_eval = AliasesEvaluator()
+ als_eval.visit(als_tree)
diff --git a/src/cli.py b/src/cli.py
index ee36f7c..4cf6668 100644
--- a/src/cli.py
+++ b/src/cli.py
@@ -24,6 +24,7 @@
import time
from pathlib import Path
+import build_supervisor
import log
from exception import AbstractError
from project import Project
@@ -57,8 +58,10 @@ def _log_boot_info():
log.info('Zoia - a language for writing fiction.')
_log_version()
log.info('Copyright (C) 2021-2022 Infernio')
- log.info('This is free software licensed under the GPLv3. See the LICENSE '
- 'file included with this program for more information.')
+ log.info('This is free software licensed under the GPLv3.')
+ log.info('See the LICENSE file included with this program for more '
+ 'information.')
+ log.info('')
_ZOIA_VERSION = '0.1'
def _log_version():
@@ -69,11 +72,11 @@ class _Verb:
"""Base class for verbs."""
def run(self, args: list[str]) -> None:
"""Runs this verb on the specified arguments."""
- raise AbstractError(self.run)
+ raise AbstractError()
class _CommonVerb(_Verb):
- """Base class for verbs that share a simple pattern of behavior: logging
- the standard boot info at startup and printing errors/warnings at exit."""
+ """Base class for verbs that share a pattern of behavior: logging the
+ standard boot info at startup and printing errors/warnings at exit."""
def run(self, args: list[str]) -> None:
_log_boot_info()
self._run_common(args)
@@ -82,15 +85,50 @@ def run(self, args: list[str]) -> None:
def _run_common(self, args: list[str]) -> None:
"""Implements the verb-specific behavior (everything besides the
boot/exit logging)."""
- raise AbstractError(self._run_common)
+ raise AbstractError()
+
+class _ProjectVerb(_CommonVerb):
+ """Base class for common verbs that share an additional pattern of
+ behavior: parsing a project from the first argument or CWD, while keeping
+ track of time elapsed."""
+ _time_msg: str
-class _Build(_CommonVerb):
- """Verb that builds a project."""
def _run_common(self, args: list[str]) -> None:
start_time = time.time()
- Project.parse_project(Path.cwd())
+ match len(args):
+ case 0:
+ final_path = Path.cwd()
+ case 1:
+ final_path = Path(args[0])
+ case _:
+ print('Usage: zoia build [path]', file=sys.stderr)
+ sys.exit(1)
+ project = Project.parse_project(final_path)
+ if project is not None:
+ self._run_on_project(project)
+ else:
+ log.warning('Aborting build due to errors while parsing project')
duration = time.time() - start_time
- log.info(f'Build took {duration:.1f}s')
+ log.info(self._time_msg % f'{duration:.1f}')
+
+ def _run_on_project(self, project: Project) -> None:
+ """Implements the verb-specific behavior using the project."""
+ raise AbstractError()
+
+class _Build(_ProjectVerb):
+ """Verb that builds a project."""
+ _time_msg = 'Build took %ss'
+
+ def _run_on_project(self, project: Project) -> None:
+ build_supervisor.build(project)
+
+class _Check(_ProjectVerb):
+ """Verb that checks a project for spelling, grammar, style, etc.
+ errors."""
+ _time_msg = 'Check took %ss'
+
+ def _run_on_project(self, project: Path) -> None:
+ pass # TODO implement checking
class _Version(_Verb):
"""Verb that prints the Zoia version and exits."""
@@ -99,6 +137,7 @@ def run(self, args: list[str]) -> None:
_verbs = {
'build': _Build(),
+ 'check': _Check(),
'version': _Version(),
}
diff --git a/src/exception.py b/src/exception.py
index f37ebba..41679d4 100644
--- a/src/exception.py
+++ b/src/exception.py
@@ -20,6 +20,8 @@
#
# =============================================================================
"""This module contains all custom exceptions for Zoia."""
+import inspect
+import os
from os import PathLike
from src_pos import SourcePos
@@ -27,33 +29,51 @@
class AbstractError(Exception):
"""Abstract section of code called."""
- def __init__(self, abs_method: callable) -> None:
- super().__init__(f"Abstract method '{abs_method.__qualname__}' was "
- f"called")
+ def __init__(self) -> None:
+ call_stack = inspect.stack()
+ or_file, or_line, or_function = call_stack[1][1:4]
+ super().__init__(f"Abstract method '{or_function}' (at "
+ f"{os.path.basename(or_file)}:{or_line}) "
+ f"was called")
class _SrcPosError(Exception):
"""Base class for errors that carry information about where in a source
file they occurred."""
- def __init__(self, pos: SourcePos, msg: str) -> None:
+ def __init__(self, msg: str, pos: SourcePos, orig_msg: str) -> None:
super().__init__(msg)
self.src_pos = pos
+ self.orig_msg = orig_msg
+
+class EvalError(_SrcPosError):
+ """An error that occurred during evaluation."""
+ def __init__(self, pos: SourcePos, msg: str) -> None:
+ super().__init__(f'Failed to evaluate {pos.src_file} at line '
+ f'{pos.src_line}, column {pos.src_char}: {msg}',
+ pos, msg)
class ParseConversionError(_SrcPosError):
"""An error that occurred during parse-to-AST conversion."""
def __init__(self, pos: SourcePos, msg: str) -> None:
- super().__init__(pos, f'Failed to AST-convert {pos.src_file} at line '
- f'{pos.src_line}, column {pos.src_char}: {msg}')
- self.orig_msg = msg
+ super().__init__(f'Failed to AST-convert {pos.src_file} at line '
+ f'{pos.src_line}, column {pos.src_char}: {msg}',
+ pos, msg)
class ParsingError(_SrcPosError):
"""An error that occurred during parsing of a Zoia file."""
def __init__(self, pos: SourcePos, msg: str) -> None:
- super().__init__(pos, f'Failed to parse {pos.src_file} at line '
- f'{pos.src_line}, column {pos.src_char}: {msg}')
- self.orig_msg = msg
+ super().__init__(f'Failed to parse {pos.src_file} at line '
+ f'{pos.src_line}, column {pos.src_char}: {msg}',
+ pos, msg)
class ProjectStructureError(Exception):
"""The project structure is invalid."""
def __init__(self, relevant_path: PathLike, msg: str) -> None:
super().__init__(f"Invalid project structure at '{relevant_path}': "
f"{msg}")
+
+class ValidationError(_SrcPosError):
+ """Error while validating Zoia AST nodes."""
+ def __init__(self, pos: SourcePos, msg: str) -> None:
+ super().__init__(f'Failed to validate {pos.src_file} at line '
+ f'{pos.src_line}, column {pos.src_char}: {msg}',
+ pos, msg)
diff --git a/src/grammar/cpp/sa_zoia_translator.cpp b/src/grammar/cpp/sa_zoia_translator.cpp
index 4c9c946..2b4a4c5 100644
--- a/src/grammar/cpp/sa_zoia_translator.cpp
+++ b/src/grammar/cpp/sa_zoia_translator.cpp
@@ -16,11 +16,13 @@ SA_zoiaTranslator::~SA_zoiaTranslator() {
Py_XDECREF(LineContext_cls);
Py_XDECREF(LineElementsContext_cls);
Py_XDECREF(LineElementsInnerContext_cls);
+ Py_XDECREF(LineElementsArgContext_cls);
Py_XDECREF(Em3LineElementContext_cls);
Py_XDECREF(Em2LineElementContext_cls);
Py_XDECREF(Em1LineElementContext_cls);
Py_XDECREF(TextFragmentContext_cls);
Py_XDECREF(TextFragmentReqContext_cls);
+ Py_XDECREF(TextFragmentWordContext_cls);
Py_XDECREF(AliasContext_cls);
Py_XDECREF(CommandContext_cls);
Py_XDECREF(ArgumentsContext_cls);
@@ -61,6 +63,12 @@ antlrcpp::Any SA_zoiaTranslator::visitLineElementsInner(zoiaParser::LineElements
return py_ctx;
}
+antlrcpp::Any SA_zoiaTranslator::visitLineElementsArg(zoiaParser::LineElementsArgContext *ctx){
+ if(!LineElementsArgContext_cls) LineElementsArgContext_cls = PyObject_GetAttrString(translator->parser_cls, "LineElementsArgContext");
+ PyObject *py_ctx = translator->convert_ctx(this, ctx, LineElementsArgContext_cls);
+ return py_ctx;
+}
+
antlrcpp::Any SA_zoiaTranslator::visitEm3LineElement(zoiaParser::Em3LineElementContext *ctx){
if(!Em3LineElementContext_cls) Em3LineElementContext_cls = PyObject_GetAttrString(translator->parser_cls, "Em3LineElementContext");
PyObject *py_ctx = translator->convert_ctx(this, ctx, Em3LineElementContext_cls);
@@ -91,6 +99,12 @@ antlrcpp::Any SA_zoiaTranslator::visitTextFragmentReq(zoiaParser::TextFragmentRe
return py_ctx;
}
+antlrcpp::Any SA_zoiaTranslator::visitTextFragmentWord(zoiaParser::TextFragmentWordContext *ctx){
+ if(!TextFragmentWordContext_cls) TextFragmentWordContext_cls = PyObject_GetAttrString(translator->parser_cls, "TextFragmentWordContext");
+ PyObject *py_ctx = translator->convert_ctx(this, ctx, TextFragmentWordContext_cls);
+ return py_ctx;
+}
+
antlrcpp::Any SA_zoiaTranslator::visitAlias(zoiaParser::AliasContext *ctx){
if(!AliasContext_cls) AliasContext_cls = PyObject_GetAttrString(translator->parser_cls, "AliasContext");
PyObject *py_ctx = translator->convert_ctx(this, ctx, AliasContext_cls);
diff --git a/src/grammar/cpp/sa_zoia_translator.h b/src/grammar/cpp/sa_zoia_translator.h
index 9a1497f..45e887f 100644
--- a/src/grammar/cpp/sa_zoia_translator.h
+++ b/src/grammar/cpp/sa_zoia_translator.h
@@ -17,11 +17,13 @@ class SA_zoiaTranslator : public zoiaBaseVisitor {
PyObject *LineContext_cls = NULL;
PyObject *LineElementsContext_cls = NULL;
PyObject *LineElementsInnerContext_cls = NULL;
+ PyObject *LineElementsArgContext_cls = NULL;
PyObject *Em3LineElementContext_cls = NULL;
PyObject *Em2LineElementContext_cls = NULL;
PyObject *Em1LineElementContext_cls = NULL;
PyObject *TextFragmentContext_cls = NULL;
PyObject *TextFragmentReqContext_cls = NULL;
+ PyObject *TextFragmentWordContext_cls = NULL;
PyObject *AliasContext_cls = NULL;
PyObject *CommandContext_cls = NULL;
PyObject *ArgumentsContext_cls = NULL;
@@ -43,6 +45,8 @@ class SA_zoiaTranslator : public zoiaBaseVisitor {
antlrcpp::Any visitLineElementsInner(zoiaParser::LineElementsInnerContext *ctx);
+ antlrcpp::Any visitLineElementsArg(zoiaParser::LineElementsArgContext *ctx);
+
antlrcpp::Any visitEm3LineElement(zoiaParser::Em3LineElementContext *ctx);
antlrcpp::Any visitEm2LineElement(zoiaParser::Em2LineElementContext *ctx);
@@ -53,6 +57,8 @@ class SA_zoiaTranslator : public zoiaBaseVisitor {
antlrcpp::Any visitTextFragmentReq(zoiaParser::TextFragmentReqContext *ctx);
+ antlrcpp::Any visitTextFragmentWord(zoiaParser::TextFragmentWordContext *ctx);
+
antlrcpp::Any visitAlias(zoiaParser::AliasContext *ctx);
antlrcpp::Any visitCommand(zoiaParser::CommandContext *ctx);
diff --git a/src/grammar/cpp/zoiaBaseVisitor.h b/src/grammar/cpp/zoiaBaseVisitor.h
index fb67f18..1553842 100644
--- a/src/grammar/cpp/zoiaBaseVisitor.h
+++ b/src/grammar/cpp/zoiaBaseVisitor.h
@@ -35,6 +35,10 @@ class zoiaBaseVisitor : public zoiaVisitor {
return visitChildren(ctx);
}
+ virtual antlrcpp::Any visitLineElementsArg(zoiaParser::LineElementsArgContext *ctx) override {
+ return visitChildren(ctx);
+ }
+
virtual antlrcpp::Any visitEm3LineElement(zoiaParser::Em3LineElementContext *ctx) override {
return visitChildren(ctx);
}
@@ -55,6 +59,10 @@ class zoiaBaseVisitor : public zoiaVisitor {
return visitChildren(ctx);
}
+ virtual antlrcpp::Any visitTextFragmentWord(zoiaParser::TextFragmentWordContext *ctx) override {
+ return visitChildren(ctx);
+ }
+
virtual antlrcpp::Any visitAlias(zoiaParser::AliasContext *ctx) override {
return visitChildren(ctx);
}
diff --git a/src/grammar/cpp/zoiaParser.cpp b/src/grammar/cpp/zoiaParser.cpp
index 6463a0a..2d86281 100644
--- a/src/grammar/cpp/zoiaParser.cpp
+++ b/src/grammar/cpp/zoiaParser.cpp
@@ -80,9 +80,9 @@ zoiaParser::ZoiaFileContext* zoiaParser::zoiaFile() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(34);
- header();
setState(38);
+ header();
+ setState(42);
_errHandler->sync(this);
_la = _input->LA(1);
while ((((_la & ~ 0x3fULL) == 0) &&
@@ -92,13 +92,13 @@ zoiaParser::ZoiaFileContext* zoiaParser::zoiaFile() {
| (1ULL << zoiaParser::Newline)
| (1ULL << zoiaParser::Spaces)
| (1ULL << zoiaParser::Word))) != 0)) {
- setState(35);
+ setState(39);
line();
- setState(40);
+ setState(44);
_errHandler->sync(this);
_la = _input->LA(1);
}
- setState(41);
+ setState(45);
match(zoiaParser::EOF);
}
@@ -155,11 +155,11 @@ zoiaParser::HeaderContext* zoiaParser::header() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(43);
+ setState(47);
match(zoiaParser::Header);
- setState(44);
+ setState(48);
arguments();
- setState(45);
+ setState(49);
match(zoiaParser::Newline);
}
@@ -213,7 +213,7 @@ zoiaParser::LineContext* zoiaParser::line() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(48);
+ setState(52);
_errHandler->sync(this);
_la = _input->LA(1);
@@ -223,10 +223,10 @@ zoiaParser::LineContext* zoiaParser::line() {
| (1ULL << zoiaParser::Backslash)
| (1ULL << zoiaParser::Spaces)
| (1ULL << zoiaParser::Word))) != 0)) {
- setState(47);
+ setState(51);
lineElements();
}
- setState(50);
+ setState(54);
match(zoiaParser::Newline);
}
@@ -309,6 +309,7 @@ antlrcpp::Any zoiaParser::LineElementsContext::accept(tree::ParseTreeVisitor *vi
zoiaParser::LineElementsContext* zoiaParser::lineElements() {
LineElementsContext *_localctx = _tracker.createInstance(_ctx, getState());
enterRule(_localctx, 6, zoiaParser::RuleLineElements);
+ size_t _la = 0;
#if __cplusplus > 201703L
auto onExit = finally([=, this] {
@@ -318,66 +319,62 @@ zoiaParser::LineElementsContext* zoiaParser::lineElements() {
exitRule();
});
try {
- size_t alt;
enterOuterAlt(_localctx, 1);
- setState(58);
+ setState(62);
_errHandler->sync(this);
- alt = 1;
+ _la = _input->LA(1);
do {
- switch (alt) {
- case 1: {
- setState(58);
- _errHandler->sync(this);
- switch (getInterpreter()->adaptivePredict(_input, 2, _ctx)) {
- case 1: {
- setState(52);
- textFragment();
- break;
- }
-
- case 2: {
- setState(53);
- alias();
- break;
- }
-
- case 3: {
- setState(54);
- command();
- break;
- }
-
- case 4: {
- setState(55);
- em1LineElement();
- break;
- }
-
- case 5: {
- setState(56);
- em2LineElement();
- break;
- }
-
- case 6: {
- setState(57);
- em3LineElement();
- break;
- }
-
- default:
- break;
- }
- break;
- }
+ setState(62);
+ _errHandler->sync(this);
+ switch (getInterpreter()->adaptivePredict(_input, 2, _ctx)) {
+ case 1: {
+ setState(56);
+ textFragment();
+ break;
+ }
+
+ case 2: {
+ setState(57);
+ alias();
+ break;
+ }
+
+ case 3: {
+ setState(58);
+ command();
+ break;
+ }
+
+ case 4: {
+ setState(59);
+ em1LineElement();
+ break;
+ }
+
+ case 5: {
+ setState(60);
+ em2LineElement();
+ break;
+ }
+
+ case 6: {
+ setState(61);
+ em3LineElement();
+ break;
+ }
default:
- throw NoViableAltException(this);
+ break;
}
- setState(60);
+ setState(64);
_errHandler->sync(this);
- alt = getInterpreter()->adaptivePredict(_input, 3, _ctx);
- } while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER);
+ _la = _input->LA(1);
+ } while ((((_la & ~ 0x3fULL) == 0) &&
+ ((1ULL << _la) & ((1ULL << zoiaParser::Asterisk)
+ | (1ULL << zoiaParser::At)
+ | (1ULL << zoiaParser::Backslash)
+ | (1ULL << zoiaParser::Spaces)
+ | (1ULL << zoiaParser::Word))) != 0));
}
catch (RecognitionException &e) {
@@ -446,28 +443,28 @@ zoiaParser::LineElementsInnerContext* zoiaParser::lineElementsInner() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(65);
+ setState(69);
_errHandler->sync(this);
_la = _input->LA(1);
do {
- setState(65);
+ setState(69);
_errHandler->sync(this);
switch (_input->LA(1)) {
case zoiaParser::Spaces:
case zoiaParser::Word: {
- setState(62);
+ setState(66);
textFragmentReq();
break;
}
case zoiaParser::At: {
- setState(63);
+ setState(67);
alias();
break;
}
case zoiaParser::Backslash: {
- setState(64);
+ setState(68);
command();
break;
}
@@ -475,7 +472,7 @@ zoiaParser::LineElementsInnerContext* zoiaParser::lineElementsInner() {
default:
throw NoViableAltException(this);
}
- setState(67);
+ setState(71);
_errHandler->sync(this);
_la = _input->LA(1);
} while ((((_la & ~ 0x3fULL) == 0) &&
@@ -494,6 +491,196 @@ zoiaParser::LineElementsInnerContext* zoiaParser::lineElementsInner() {
return _localctx;
}
+//----------------- LineElementsArgContext ------------------------------------------------------------------
+
+zoiaParser::LineElementsArgContext::LineElementsArgContext(ParserRuleContext *parent, size_t invokingState)
+ : ParserRuleContext(parent, invokingState) {
+}
+
+zoiaParser::TextFragmentWordContext* zoiaParser::LineElementsArgContext::textFragmentWord() {
+ return getRuleContext(0);
+}
+
+std::vector zoiaParser::LineElementsArgContext::alias() {
+ return getRuleContexts();
+}
+
+zoiaParser::AliasContext* zoiaParser::LineElementsArgContext::alias(size_t i) {
+ return getRuleContext(i);
+}
+
+std::vector zoiaParser::LineElementsArgContext::command() {
+ return getRuleContexts();
+}
+
+zoiaParser::CommandContext* zoiaParser::LineElementsArgContext::command(size_t i) {
+ return getRuleContext(i);
+}
+
+std::vector zoiaParser::LineElementsArgContext::em1LineElement() {
+ return getRuleContexts();
+}
+
+zoiaParser::Em1LineElementContext* zoiaParser::LineElementsArgContext::em1LineElement(size_t i) {
+ return getRuleContext(i);
+}
+
+std::vector zoiaParser::LineElementsArgContext::em2LineElement() {
+ return getRuleContexts();
+}
+
+zoiaParser::Em2LineElementContext* zoiaParser::LineElementsArgContext::em2LineElement(size_t i) {
+ return getRuleContext(i);
+}
+
+std::vector zoiaParser::LineElementsArgContext::em3LineElement() {
+ return getRuleContexts();
+}
+
+zoiaParser::Em3LineElementContext* zoiaParser::LineElementsArgContext::em3LineElement(size_t i) {
+ return getRuleContext(i);
+}
+
+std::vector zoiaParser::LineElementsArgContext::textFragment() {
+ return getRuleContexts();
+}
+
+zoiaParser::TextFragmentContext* zoiaParser::LineElementsArgContext::textFragment(size_t i) {
+ return getRuleContext(i);
+}
+
+
+size_t zoiaParser::LineElementsArgContext::getRuleIndex() const {
+ return zoiaParser::RuleLineElementsArg;
+}
+
+
+antlrcpp::Any zoiaParser::LineElementsArgContext::accept(tree::ParseTreeVisitor *visitor) {
+ if (auto parserVisitor = dynamic_cast(visitor))
+ return parserVisitor->visitLineElementsArg(this);
+ else
+ return visitor->visitChildren(this);
+}
+
+zoiaParser::LineElementsArgContext* zoiaParser::lineElementsArg() {
+ LineElementsArgContext *_localctx = _tracker.createInstance(_ctx, getState());
+ enterRule(_localctx, 10, zoiaParser::RuleLineElementsArg);
+
+#if __cplusplus > 201703L
+ auto onExit = finally([=, this] {
+#else
+ auto onExit = finally([=] {
+#endif
+ exitRule();
+ });
+ try {
+ size_t alt;
+ enterOuterAlt(_localctx, 1);
+ setState(79);
+ _errHandler->sync(this);
+ switch (getInterpreter()->adaptivePredict(_input, 6, _ctx)) {
+ case 1: {
+ setState(73);
+ textFragmentWord();
+ break;
+ }
+
+ case 2: {
+ setState(74);
+ alias();
+ break;
+ }
+
+ case 3: {
+ setState(75);
+ command();
+ break;
+ }
+
+ case 4: {
+ setState(76);
+ em1LineElement();
+ break;
+ }
+
+ case 5: {
+ setState(77);
+ em2LineElement();
+ break;
+ }
+
+ case 6: {
+ setState(78);
+ em3LineElement();
+ break;
+ }
+
+ default:
+ break;
+ }
+ setState(89);
+ _errHandler->sync(this);
+ alt = getInterpreter()->adaptivePredict(_input, 8, _ctx);
+ while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) {
+ if (alt == 1) {
+ setState(87);
+ _errHandler->sync(this);
+ switch (getInterpreter()->adaptivePredict(_input, 7, _ctx)) {
+ case 1: {
+ setState(81);
+ textFragment();
+ break;
+ }
+
+ case 2: {
+ setState(82);
+ alias();
+ break;
+ }
+
+ case 3: {
+ setState(83);
+ command();
+ break;
+ }
+
+ case 4: {
+ setState(84);
+ em1LineElement();
+ break;
+ }
+
+ case 5: {
+ setState(85);
+ em2LineElement();
+ break;
+ }
+
+ case 6: {
+ setState(86);
+ em3LineElement();
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ setState(91);
+ _errHandler->sync(this);
+ alt = getInterpreter()->adaptivePredict(_input, 8, _ctx);
+ }
+
+ }
+ catch (RecognitionException &e) {
+ _errHandler->reportError(this, e);
+ _localctx->exception = std::current_exception();
+ _errHandler->recover(this, _localctx->exception);
+ }
+
+ return _localctx;
+}
+
//----------------- Em3LineElementContext ------------------------------------------------------------------
zoiaParser::Em3LineElementContext::Em3LineElementContext(ParserRuleContext *parent, size_t invokingState)
@@ -527,7 +714,7 @@ antlrcpp::Any zoiaParser::Em3LineElementContext::accept(tree::ParseTreeVisitor *
zoiaParser::Em3LineElementContext* zoiaParser::em3LineElement() {
Em3LineElementContext *_localctx = _tracker.createInstance(_ctx, getState());
- enterRule(_localctx, 10, zoiaParser::RuleEm3LineElement);
+ enterRule(_localctx, 12, zoiaParser::RuleEm3LineElement);
#if __cplusplus > 201703L
auto onExit = finally([=, this] {
@@ -538,19 +725,19 @@ zoiaParser::Em3LineElementContext* zoiaParser::em3LineElement() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(69);
+ setState(92);
match(zoiaParser::Asterisk);
- setState(70);
+ setState(93);
match(zoiaParser::Asterisk);
- setState(71);
+ setState(94);
match(zoiaParser::Asterisk);
- setState(72);
+ setState(95);
lineElementsInner();
- setState(73);
+ setState(96);
match(zoiaParser::Asterisk);
- setState(74);
+ setState(97);
match(zoiaParser::Asterisk);
- setState(75);
+ setState(98);
match(zoiaParser::Asterisk);
}
@@ -596,7 +783,7 @@ antlrcpp::Any zoiaParser::Em2LineElementContext::accept(tree::ParseTreeVisitor *
zoiaParser::Em2LineElementContext* zoiaParser::em2LineElement() {
Em2LineElementContext *_localctx = _tracker.createInstance(_ctx, getState());
- enterRule(_localctx, 12, zoiaParser::RuleEm2LineElement);
+ enterRule(_localctx, 14, zoiaParser::RuleEm2LineElement);
#if __cplusplus > 201703L
auto onExit = finally([=, this] {
@@ -607,15 +794,15 @@ zoiaParser::Em2LineElementContext* zoiaParser::em2LineElement() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(77);
+ setState(100);
match(zoiaParser::Asterisk);
- setState(78);
+ setState(101);
match(zoiaParser::Asterisk);
- setState(79);
+ setState(102);
lineElementsInner();
- setState(80);
+ setState(103);
match(zoiaParser::Asterisk);
- setState(81);
+ setState(104);
match(zoiaParser::Asterisk);
}
@@ -661,7 +848,7 @@ antlrcpp::Any zoiaParser::Em1LineElementContext::accept(tree::ParseTreeVisitor *
zoiaParser::Em1LineElementContext* zoiaParser::em1LineElement() {
Em1LineElementContext *_localctx = _tracker.createInstance(_ctx, getState());
- enterRule(_localctx, 14, zoiaParser::RuleEm1LineElement);
+ enterRule(_localctx, 16, zoiaParser::RuleEm1LineElement);
#if __cplusplus > 201703L
auto onExit = finally([=, this] {
@@ -672,11 +859,11 @@ zoiaParser::Em1LineElementContext* zoiaParser::em1LineElement() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(83);
+ setState(106);
match(zoiaParser::Asterisk);
- setState(84);
+ setState(107);
lineElementsInner();
- setState(85);
+ setState(108);
match(zoiaParser::Asterisk);
}
@@ -718,7 +905,7 @@ antlrcpp::Any zoiaParser::TextFragmentContext::accept(tree::ParseTreeVisitor *vi
zoiaParser::TextFragmentContext* zoiaParser::textFragment() {
TextFragmentContext *_localctx = _tracker.createInstance(_ctx, getState());
- enterRule(_localctx, 16, zoiaParser::RuleTextFragment);
+ enterRule(_localctx, 18, zoiaParser::RuleTextFragment);
size_t _la = 0;
#if __cplusplus > 201703L
@@ -730,7 +917,7 @@ zoiaParser::TextFragmentContext* zoiaParser::textFragment() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(87);
+ setState(110);
_la = _input->LA(1);
if (!(_la == zoiaParser::Spaces
@@ -785,7 +972,7 @@ antlrcpp::Any zoiaParser::TextFragmentReqContext::accept(tree::ParseTreeVisitor
zoiaParser::TextFragmentReqContext* zoiaParser::textFragmentReq() {
TextFragmentReqContext *_localctx = _tracker.createInstance(_ctx, getState());
- enterRule(_localctx, 18, zoiaParser::RuleTextFragmentReq);
+ enterRule(_localctx, 20, zoiaParser::RuleTextFragmentReq);
size_t _la = 0;
#if __cplusplus > 201703L
@@ -797,22 +984,88 @@ zoiaParser::TextFragmentReqContext* zoiaParser::textFragmentReq() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(90);
+ setState(113);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == zoiaParser::Spaces) {
- setState(89);
+ setState(112);
match(zoiaParser::Spaces);
}
- setState(92);
+ setState(115);
match(zoiaParser::Word);
- setState(94);
+ setState(117);
+ _errHandler->sync(this);
+
+ switch (getInterpreter()->adaptivePredict(_input, 10, _ctx)) {
+ case 1: {
+ setState(116);
+ match(zoiaParser::Spaces);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ }
+ catch (RecognitionException &e) {
+ _errHandler->reportError(this, e);
+ _localctx->exception = std::current_exception();
+ _errHandler->recover(this, _localctx->exception);
+ }
+
+ return _localctx;
+}
+
+//----------------- TextFragmentWordContext ------------------------------------------------------------------
+
+zoiaParser::TextFragmentWordContext::TextFragmentWordContext(ParserRuleContext *parent, size_t invokingState)
+ : ParserRuleContext(parent, invokingState) {
+}
+
+tree::TerminalNode* zoiaParser::TextFragmentWordContext::Word() {
+ return getToken(zoiaParser::Word, 0);
+}
+
+tree::TerminalNode* zoiaParser::TextFragmentWordContext::Spaces() {
+ return getToken(zoiaParser::Spaces, 0);
+}
+
+
+size_t zoiaParser::TextFragmentWordContext::getRuleIndex() const {
+ return zoiaParser::RuleTextFragmentWord;
+}
+
+
+antlrcpp::Any zoiaParser::TextFragmentWordContext::accept(tree::ParseTreeVisitor *visitor) {
+ if (auto parserVisitor = dynamic_cast(visitor))
+ return parserVisitor->visitTextFragmentWord(this);
+ else
+ return visitor->visitChildren(this);
+}
+
+zoiaParser::TextFragmentWordContext* zoiaParser::textFragmentWord() {
+ TextFragmentWordContext *_localctx = _tracker.createInstance(_ctx, getState());
+ enterRule(_localctx, 22, zoiaParser::RuleTextFragmentWord);
+
+#if __cplusplus > 201703L
+ auto onExit = finally([=, this] {
+#else
+ auto onExit = finally([=] {
+#endif
+ exitRule();
+ });
+ try {
+ enterOuterAlt(_localctx, 1);
+ setState(119);
+ match(zoiaParser::Word);
+ setState(121);
_errHandler->sync(this);
- switch (getInterpreter()->adaptivePredict(_input, 7, _ctx)) {
+ switch (getInterpreter()->adaptivePredict(_input, 11, _ctx)) {
case 1: {
- setState(93);
+ setState(120);
match(zoiaParser::Spaces);
break;
}
@@ -864,7 +1117,7 @@ antlrcpp::Any zoiaParser::AliasContext::accept(tree::ParseTreeVisitor *visitor)
zoiaParser::AliasContext* zoiaParser::alias() {
AliasContext *_localctx = _tracker.createInstance(_ctx, getState());
- enterRule(_localctx, 20, zoiaParser::RuleAlias);
+ enterRule(_localctx, 24, zoiaParser::RuleAlias);
size_t _la = 0;
#if __cplusplus > 201703L
@@ -876,16 +1129,16 @@ zoiaParser::AliasContext* zoiaParser::alias() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(96);
+ setState(123);
match(zoiaParser::At);
- setState(97);
+ setState(124);
match(zoiaParser::Word);
- setState(99);
+ setState(126);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == zoiaParser::Bar) {
- setState(98);
+ setState(125);
match(zoiaParser::Bar);
}
@@ -936,7 +1189,7 @@ antlrcpp::Any zoiaParser::CommandContext::accept(tree::ParseTreeVisitor *visitor
zoiaParser::CommandContext* zoiaParser::command() {
CommandContext *_localctx = _tracker.createInstance(_ctx, getState());
- enterRule(_localctx, 22, zoiaParser::RuleCommand);
+ enterRule(_localctx, 26, zoiaParser::RuleCommand);
size_t _la = 0;
#if __cplusplus > 201703L
@@ -948,24 +1201,24 @@ zoiaParser::CommandContext* zoiaParser::command() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(101);
+ setState(128);
match(zoiaParser::Backslash);
- setState(102);
+ setState(129);
match(zoiaParser::Word);
- setState(104);
+ setState(131);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == zoiaParser::BracketsOpen) {
- setState(103);
+ setState(130);
arguments();
}
- setState(107);
+ setState(134);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == zoiaParser::Bar) {
- setState(106);
+ setState(133);
match(zoiaParser::Bar);
}
@@ -1032,7 +1285,7 @@ antlrcpp::Any zoiaParser::ArgumentsContext::accept(tree::ParseTreeVisitor *visit
zoiaParser::ArgumentsContext* zoiaParser::arguments() {
ArgumentsContext *_localctx = _tracker.createInstance(_ctx, getState());
- enterRule(_localctx, 24, zoiaParser::RuleArguments);
+ enterRule(_localctx, 28, zoiaParser::RuleArguments);
size_t _la = 0;
#if __cplusplus > 201703L
@@ -1045,69 +1298,63 @@ zoiaParser::ArgumentsContext* zoiaParser::arguments() {
try {
size_t alt;
enterOuterAlt(_localctx, 1);
- setState(109);
+ setState(136);
match(zoiaParser::BracketsOpen);
- setState(111);
+ setState(138);
_errHandler->sync(this);
- switch (getInterpreter()->adaptivePredict(_input, 11, _ctx)) {
- case 1: {
- setState(110);
- whitespace();
- break;
- }
+ _la = _input->LA(1);
+ if (_la == zoiaParser::Newline
- default:
- break;
+ || _la == zoiaParser::Spaces) {
+ setState(137);
+ whitespace();
}
- setState(113);
+ setState(140);
argument();
- setState(121);
+ setState(148);
_errHandler->sync(this);
- alt = getInterpreter()->adaptivePredict(_input, 13, _ctx);
+ alt = getInterpreter()->adaptivePredict(_input, 17, _ctx);
while (alt != 1 && alt != atn::ATN::INVALID_ALT_NUMBER) {
if (alt == 1 + 1) {
- setState(114);
+ setState(141);
match(zoiaParser::Semicolon);
- setState(116);
+ setState(143);
_errHandler->sync(this);
- switch (getInterpreter()->adaptivePredict(_input, 12, _ctx)) {
- case 1: {
- setState(115);
- whitespace();
- break;
- }
+ _la = _input->LA(1);
+ if (_la == zoiaParser::Newline
- default:
- break;
+ || _la == zoiaParser::Spaces) {
+ setState(142);
+ whitespace();
}
- setState(118);
+ setState(145);
argument();
}
- setState(123);
+ setState(150);
_errHandler->sync(this);
- alt = getInterpreter()->adaptivePredict(_input, 13, _ctx);
+ alt = getInterpreter()->adaptivePredict(_input, 17, _ctx);
}
- setState(125);
+ setState(152);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == zoiaParser::Semicolon) {
- setState(124);
+ setState(151);
match(zoiaParser::Semicolon);
}
- setState(128);
+ setState(155);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == zoiaParser::Newline
|| _la == zoiaParser::Spaces) {
- setState(127);
+ setState(154);
whitespace();
}
- setState(130);
+ setState(157);
match(zoiaParser::BracketsClose);
}
@@ -1149,7 +1396,7 @@ antlrcpp::Any zoiaParser::ArgumentContext::accept(tree::ParseTreeVisitor *visito
zoiaParser::ArgumentContext* zoiaParser::argument() {
ArgumentContext *_localctx = _tracker.createInstance(_ctx, getState());
- enterRule(_localctx, 26, zoiaParser::RuleArgument);
+ enterRule(_localctx, 30, zoiaParser::RuleArgument);
#if __cplusplus > 201703L
auto onExit = finally([=, this] {
@@ -1159,19 +1406,19 @@ zoiaParser::ArgumentContext* zoiaParser::argument() {
exitRule();
});
try {
- setState(134);
+ setState(161);
_errHandler->sync(this);
- switch (getInterpreter()->adaptivePredict(_input, 16, _ctx)) {
+ switch (getInterpreter()->adaptivePredict(_input, 20, _ctx)) {
case 1: {
enterOuterAlt(_localctx, 1);
- setState(132);
+ setState(159);
kwdArgument();
break;
}
case 2: {
enterOuterAlt(_localctx, 2);
- setState(133);
+ setState(160);
stdArgument();
break;
}
@@ -1204,8 +1451,8 @@ tree::TerminalNode* zoiaParser::KwdArgumentContext::Equals() {
return getToken(zoiaParser::Equals, 0);
}
-zoiaParser::LineElementsContext* zoiaParser::KwdArgumentContext::lineElements() {
- return getRuleContext(0);
+zoiaParser::LineElementsArgContext* zoiaParser::KwdArgumentContext::lineElementsArg() {
+ return getRuleContext(0);
}
std::vector zoiaParser::KwdArgumentContext::Spaces() {
@@ -1231,7 +1478,7 @@ antlrcpp::Any zoiaParser::KwdArgumentContext::accept(tree::ParseTreeVisitor *vis
zoiaParser::KwdArgumentContext* zoiaParser::kwdArgument() {
KwdArgumentContext *_localctx = _tracker.createInstance(_ctx, getState());
- enterRule(_localctx, 28, zoiaParser::RuleKwdArgument);
+ enterRule(_localctx, 32, zoiaParser::RuleKwdArgument);
size_t _la = 0;
#if __cplusplus > 201703L
@@ -1243,33 +1490,28 @@ zoiaParser::KwdArgumentContext* zoiaParser::kwdArgument() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(136);
+ setState(163);
match(zoiaParser::Word);
- setState(138);
+ setState(165);
_errHandler->sync(this);
_la = _input->LA(1);
if (_la == zoiaParser::Spaces) {
- setState(137);
+ setState(164);
match(zoiaParser::Spaces);
}
- setState(140);
+ setState(167);
match(zoiaParser::Equals);
- setState(142);
+ setState(169);
_errHandler->sync(this);
- switch (getInterpreter()->adaptivePredict(_input, 18, _ctx)) {
- case 1: {
- setState(141);
+ _la = _input->LA(1);
+ if (_la == zoiaParser::Spaces) {
+ setState(168);
match(zoiaParser::Spaces);
- break;
}
-
- default:
- break;
- }
- setState(144);
- lineElements();
+ setState(171);
+ lineElementsArg();
}
catch (RecognitionException &e) {
@@ -1287,8 +1529,8 @@ zoiaParser::StdArgumentContext::StdArgumentContext(ParserRuleContext *parent, si
: ParserRuleContext(parent, invokingState) {
}
-zoiaParser::LineElementsContext* zoiaParser::StdArgumentContext::lineElements() {
- return getRuleContext(0);
+zoiaParser::LineElementsArgContext* zoiaParser::StdArgumentContext::lineElementsArg() {
+ return getRuleContext(0);
}
@@ -1306,7 +1548,7 @@ antlrcpp::Any zoiaParser::StdArgumentContext::accept(tree::ParseTreeVisitor *vis
zoiaParser::StdArgumentContext* zoiaParser::stdArgument() {
StdArgumentContext *_localctx = _tracker.createInstance(_ctx, getState());
- enterRule(_localctx, 30, zoiaParser::RuleStdArgument);
+ enterRule(_localctx, 34, zoiaParser::RuleStdArgument);
#if __cplusplus > 201703L
auto onExit = finally([=, this] {
@@ -1317,8 +1559,8 @@ zoiaParser::StdArgumentContext* zoiaParser::stdArgument() {
});
try {
enterOuterAlt(_localctx, 1);
- setState(146);
- lineElements();
+ setState(173);
+ lineElementsArg();
}
catch (RecognitionException &e) {
@@ -1367,7 +1609,7 @@ antlrcpp::Any zoiaParser::WhitespaceContext::accept(tree::ParseTreeVisitor *visi
zoiaParser::WhitespaceContext* zoiaParser::whitespace() {
WhitespaceContext *_localctx = _tracker.createInstance(_ctx, getState());
- enterRule(_localctx, 32, zoiaParser::RuleWhitespace);
+ enterRule(_localctx, 36, zoiaParser::RuleWhitespace);
size_t _la = 0;
#if __cplusplus > 201703L
@@ -1378,35 +1620,28 @@ zoiaParser::WhitespaceContext* zoiaParser::whitespace() {
exitRule();
});
try {
- size_t alt;
enterOuterAlt(_localctx, 1);
- setState(149);
+ setState(176);
_errHandler->sync(this);
- alt = 1;
+ _la = _input->LA(1);
do {
- switch (alt) {
- case 1: {
- setState(148);
- _la = _input->LA(1);
- if (!(_la == zoiaParser::Newline
-
- || _la == zoiaParser::Spaces)) {
- _errHandler->recoverInline(this);
- }
- else {
- _errHandler->reportMatch(this);
- consume();
- }
- break;
- }
+ setState(175);
+ _la = _input->LA(1);
+ if (!(_la == zoiaParser::Newline
- default:
- throw NoViableAltException(this);
+ || _la == zoiaParser::Spaces)) {
+ _errHandler->recoverInline(this);
}
- setState(151);
+ else {
+ _errHandler->reportMatch(this);
+ consume();
+ }
+ setState(178);
_errHandler->sync(this);
- alt = getInterpreter()->adaptivePredict(_input, 19, _ctx);
- } while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER);
+ _la = _input->LA(1);
+ } while (_la == zoiaParser::Newline
+
+ || _la == zoiaParser::Spaces);
}
catch (RecognitionException &e) {
@@ -1427,10 +1662,10 @@ atn::ATN zoiaParser::_atn;
std::vector zoiaParser::_serializedATN;
std::vector zoiaParser::_ruleNames = {
- "zoiaFile", "header", "line", "lineElements", "lineElementsInner", "em3LineElement",
- "em2LineElement", "em1LineElement", "textFragment", "textFragmentReq",
- "alias", "command", "arguments", "argument", "kwdArgument", "stdArgument",
- "whitespace"
+ "zoiaFile", "header", "line", "lineElements", "lineElementsInner", "lineElementsArg",
+ "em3LineElement", "em2LineElement", "em1LineElement", "textFragment",
+ "textFragmentReq", "textFragmentWord", "alias", "command", "arguments",
+ "argument", "kwdArgument", "stdArgument", "whitespace"
};
std::vector zoiaParser::_literalNames = {
@@ -1464,112 +1699,135 @@ zoiaParser::Initializer::Initializer() {
static const uint16_t serializedATNSegment0[] = {
0x3, 0x608b, 0xa72a, 0x8133, 0xb9ed, 0x417c, 0x3be7, 0x7786, 0x5964,
- 0x3, 0xf, 0x9c, 0x4, 0x2, 0x9, 0x2, 0x4, 0x3, 0x9, 0x3, 0x4, 0x4,
+ 0x3, 0xf, 0xb7, 0x4, 0x2, 0x9, 0x2, 0x4, 0x3, 0x9, 0x3, 0x4, 0x4,
0x9, 0x4, 0x4, 0x5, 0x9, 0x5, 0x4, 0x6, 0x9, 0x6, 0x4, 0x7, 0x9,
0x7, 0x4, 0x8, 0x9, 0x8, 0x4, 0x9, 0x9, 0x9, 0x4, 0xa, 0x9, 0xa,
0x4, 0xb, 0x9, 0xb, 0x4, 0xc, 0x9, 0xc, 0x4, 0xd, 0x9, 0xd, 0x4,
0xe, 0x9, 0xe, 0x4, 0xf, 0x9, 0xf, 0x4, 0x10, 0x9, 0x10, 0x4, 0x11,
- 0x9, 0x11, 0x4, 0x12, 0x9, 0x12, 0x3, 0x2, 0x3, 0x2, 0x7, 0x2, 0x27,
- 0xa, 0x2, 0xc, 0x2, 0xe, 0x2, 0x2a, 0xb, 0x2, 0x3, 0x2, 0x3, 0x2,
- 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x5, 0x4, 0x33,
- 0xa, 0x4, 0x3, 0x4, 0x3, 0x4, 0x3, 0x5, 0x3, 0x5, 0x3, 0x5, 0x3,
- 0x5, 0x3, 0x5, 0x3, 0x5, 0x6, 0x5, 0x3d, 0xa, 0x5, 0xd, 0x5, 0xe,
- 0x5, 0x3e, 0x3, 0x6, 0x3, 0x6, 0x3, 0x6, 0x6, 0x6, 0x44, 0xa, 0x6,
- 0xd, 0x6, 0xe, 0x6, 0x45, 0x3, 0x7, 0x3, 0x7, 0x3, 0x7, 0x3, 0x7,
- 0x3, 0x7, 0x3, 0x7, 0x3, 0x7, 0x3, 0x7, 0x3, 0x8, 0x3, 0x8, 0x3,
- 0x8, 0x3, 0x8, 0x3, 0x8, 0x3, 0x8, 0x3, 0x9, 0x3, 0x9, 0x3, 0x9,
- 0x3, 0x9, 0x3, 0xa, 0x3, 0xa, 0x3, 0xb, 0x5, 0xb, 0x5d, 0xa, 0xb,
- 0x3, 0xb, 0x3, 0xb, 0x5, 0xb, 0x61, 0xa, 0xb, 0x3, 0xc, 0x3, 0xc,
- 0x3, 0xc, 0x5, 0xc, 0x66, 0xa, 0xc, 0x3, 0xd, 0x3, 0xd, 0x3, 0xd,
- 0x5, 0xd, 0x6b, 0xa, 0xd, 0x3, 0xd, 0x5, 0xd, 0x6e, 0xa, 0xd, 0x3,
- 0xe, 0x3, 0xe, 0x5, 0xe, 0x72, 0xa, 0xe, 0x3, 0xe, 0x3, 0xe, 0x3,
- 0xe, 0x5, 0xe, 0x77, 0xa, 0xe, 0x3, 0xe, 0x7, 0xe, 0x7a, 0xa, 0xe,
- 0xc, 0xe, 0xe, 0xe, 0x7d, 0xb, 0xe, 0x3, 0xe, 0x5, 0xe, 0x80, 0xa,
- 0xe, 0x3, 0xe, 0x5, 0xe, 0x83, 0xa, 0xe, 0x3, 0xe, 0x3, 0xe, 0x3,
- 0xf, 0x3, 0xf, 0x5, 0xf, 0x89, 0xa, 0xf, 0x3, 0x10, 0x3, 0x10, 0x5,
- 0x10, 0x8d, 0xa, 0x10, 0x3, 0x10, 0x3, 0x10, 0x5, 0x10, 0x91, 0xa,
- 0x10, 0x3, 0x10, 0x3, 0x10, 0x3, 0x11, 0x3, 0x11, 0x3, 0x12, 0x6,
- 0x12, 0x98, 0xa, 0x12, 0xd, 0x12, 0xe, 0x12, 0x99, 0x3, 0x12, 0x3,
- 0x7b, 0x2, 0x13, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, 0x12, 0x14,
- 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x2, 0x4, 0x3, 0x2, 0xe,
- 0xf, 0x4, 0x2, 0xc, 0xc, 0xe, 0xe, 0x2, 0xa3, 0x2, 0x24, 0x3, 0x2,
- 0x2, 0x2, 0x4, 0x2d, 0x3, 0x2, 0x2, 0x2, 0x6, 0x32, 0x3, 0x2, 0x2,
- 0x2, 0x8, 0x3c, 0x3, 0x2, 0x2, 0x2, 0xa, 0x43, 0x3, 0x2, 0x2, 0x2,
- 0xc, 0x47, 0x3, 0x2, 0x2, 0x2, 0xe, 0x4f, 0x3, 0x2, 0x2, 0x2, 0x10,
- 0x55, 0x3, 0x2, 0x2, 0x2, 0x12, 0x59, 0x3, 0x2, 0x2, 0x2, 0x14, 0x5c,
- 0x3, 0x2, 0x2, 0x2, 0x16, 0x62, 0x3, 0x2, 0x2, 0x2, 0x18, 0x67, 0x3,
- 0x2, 0x2, 0x2, 0x1a, 0x6f, 0x3, 0x2, 0x2, 0x2, 0x1c, 0x88, 0x3, 0x2,
- 0x2, 0x2, 0x1e, 0x8a, 0x3, 0x2, 0x2, 0x2, 0x20, 0x94, 0x3, 0x2, 0x2,
- 0x2, 0x22, 0x97, 0x3, 0x2, 0x2, 0x2, 0x24, 0x28, 0x5, 0x4, 0x3, 0x2,
- 0x25, 0x27, 0x5, 0x6, 0x4, 0x2, 0x26, 0x25, 0x3, 0x2, 0x2, 0x2, 0x27,
- 0x2a, 0x3, 0x2, 0x2, 0x2, 0x28, 0x26, 0x3, 0x2, 0x2, 0x2, 0x28, 0x29,
- 0x3, 0x2, 0x2, 0x2, 0x29, 0x2b, 0x3, 0x2, 0x2, 0x2, 0x2a, 0x28, 0x3,
- 0x2, 0x2, 0x2, 0x2b, 0x2c, 0x7, 0x2, 0x2, 0x3, 0x2c, 0x3, 0x3, 0x2,
- 0x2, 0x2, 0x2d, 0x2e, 0x7, 0xb, 0x2, 0x2, 0x2e, 0x2f, 0x5, 0x1a,
- 0xe, 0x2, 0x2f, 0x30, 0x7, 0xc, 0x2, 0x2, 0x30, 0x5, 0x3, 0x2, 0x2,
- 0x2, 0x31, 0x33, 0x5, 0x8, 0x5, 0x2, 0x32, 0x31, 0x3, 0x2, 0x2, 0x2,
- 0x32, 0x33, 0x3, 0x2, 0x2, 0x2, 0x33, 0x34, 0x3, 0x2, 0x2, 0x2, 0x34,
- 0x35, 0x7, 0xc, 0x2, 0x2, 0x35, 0x7, 0x3, 0x2, 0x2, 0x2, 0x36, 0x3d,
- 0x5, 0x12, 0xa, 0x2, 0x37, 0x3d, 0x5, 0x16, 0xc, 0x2, 0x38, 0x3d,
- 0x5, 0x18, 0xd, 0x2, 0x39, 0x3d, 0x5, 0x10, 0x9, 0x2, 0x3a, 0x3d,
- 0x5, 0xe, 0x8, 0x2, 0x3b, 0x3d, 0x5, 0xc, 0x7, 0x2, 0x3c, 0x36, 0x3,
- 0x2, 0x2, 0x2, 0x3c, 0x37, 0x3, 0x2, 0x2, 0x2, 0x3c, 0x38, 0x3, 0x2,
- 0x2, 0x2, 0x3c, 0x39, 0x3, 0x2, 0x2, 0x2, 0x3c, 0x3a, 0x3, 0x2, 0x2,
- 0x2, 0x3c, 0x3b, 0x3, 0x2, 0x2, 0x2, 0x3d, 0x3e, 0x3, 0x2, 0x2, 0x2,
- 0x3e, 0x3c, 0x3, 0x2, 0x2, 0x2, 0x3e, 0x3f, 0x3, 0x2, 0x2, 0x2, 0x3f,
- 0x9, 0x3, 0x2, 0x2, 0x2, 0x40, 0x44, 0x5, 0x14, 0xb, 0x2, 0x41, 0x44,
- 0x5, 0x16, 0xc, 0x2, 0x42, 0x44, 0x5, 0x18, 0xd, 0x2, 0x43, 0x40,
- 0x3, 0x2, 0x2, 0x2, 0x43, 0x41, 0x3, 0x2, 0x2, 0x2, 0x43, 0x42, 0x3,
- 0x2, 0x2, 0x2, 0x44, 0x45, 0x3, 0x2, 0x2, 0x2, 0x45, 0x43, 0x3, 0x2,
- 0x2, 0x2, 0x45, 0x46, 0x3, 0x2, 0x2, 0x2, 0x46, 0xb, 0x3, 0x2, 0x2,
- 0x2, 0x47, 0x48, 0x7, 0x4, 0x2, 0x2, 0x48, 0x49, 0x7, 0x4, 0x2, 0x2,
- 0x49, 0x4a, 0x7, 0x4, 0x2, 0x2, 0x4a, 0x4b, 0x5, 0xa, 0x6, 0x2, 0x4b,
- 0x4c, 0x7, 0x4, 0x2, 0x2, 0x4c, 0x4d, 0x7, 0x4, 0x2, 0x2, 0x4d, 0x4e,
- 0x7, 0x4, 0x2, 0x2, 0x4e, 0xd, 0x3, 0x2, 0x2, 0x2, 0x4f, 0x50, 0x7,
- 0x4, 0x2, 0x2, 0x50, 0x51, 0x7, 0x4, 0x2, 0x2, 0x51, 0x52, 0x5, 0xa,
- 0x6, 0x2, 0x52, 0x53, 0x7, 0x4, 0x2, 0x2, 0x53, 0x54, 0x7, 0x4, 0x2,
- 0x2, 0x54, 0xf, 0x3, 0x2, 0x2, 0x2, 0x55, 0x56, 0x7, 0x4, 0x2, 0x2,
- 0x56, 0x57, 0x5, 0xa, 0x6, 0x2, 0x57, 0x58, 0x7, 0x4, 0x2, 0x2, 0x58,
- 0x11, 0x3, 0x2, 0x2, 0x2, 0x59, 0x5a, 0x9, 0x2, 0x2, 0x2, 0x5a, 0x13,
- 0x3, 0x2, 0x2, 0x2, 0x5b, 0x5d, 0x7, 0xe, 0x2, 0x2, 0x5c, 0x5b, 0x3,
- 0x2, 0x2, 0x2, 0x5c, 0x5d, 0x3, 0x2, 0x2, 0x2, 0x5d, 0x5e, 0x3, 0x2,
- 0x2, 0x2, 0x5e, 0x60, 0x7, 0xf, 0x2, 0x2, 0x5f, 0x61, 0x7, 0xe, 0x2,
- 0x2, 0x60, 0x5f, 0x3, 0x2, 0x2, 0x2, 0x60, 0x61, 0x3, 0x2, 0x2, 0x2,
- 0x61, 0x15, 0x3, 0x2, 0x2, 0x2, 0x62, 0x63, 0x7, 0x5, 0x2, 0x2, 0x63,
- 0x65, 0x7, 0xf, 0x2, 0x2, 0x64, 0x66, 0x7, 0x7, 0x2, 0x2, 0x65, 0x64,
- 0x3, 0x2, 0x2, 0x2, 0x65, 0x66, 0x3, 0x2, 0x2, 0x2, 0x66, 0x17, 0x3,
- 0x2, 0x2, 0x2, 0x67, 0x68, 0x7, 0x6, 0x2, 0x2, 0x68, 0x6a, 0x7, 0xf,
- 0x2, 0x2, 0x69, 0x6b, 0x5, 0x1a, 0xe, 0x2, 0x6a, 0x69, 0x3, 0x2,
- 0x2, 0x2, 0x6a, 0x6b, 0x3, 0x2, 0x2, 0x2, 0x6b, 0x6d, 0x3, 0x2, 0x2,
- 0x2, 0x6c, 0x6e, 0x7, 0x7, 0x2, 0x2, 0x6d, 0x6c, 0x3, 0x2, 0x2, 0x2,
- 0x6d, 0x6e, 0x3, 0x2, 0x2, 0x2, 0x6e, 0x19, 0x3, 0x2, 0x2, 0x2, 0x6f,
- 0x71, 0x7, 0x9, 0x2, 0x2, 0x70, 0x72, 0x5, 0x22, 0x12, 0x2, 0x71,
- 0x70, 0x3, 0x2, 0x2, 0x2, 0x71, 0x72, 0x3, 0x2, 0x2, 0x2, 0x72, 0x73,
- 0x3, 0x2, 0x2, 0x2, 0x73, 0x7b, 0x5, 0x1c, 0xf, 0x2, 0x74, 0x76,
- 0x7, 0xd, 0x2, 0x2, 0x75, 0x77, 0x5, 0x22, 0x12, 0x2, 0x76, 0x75,
- 0x3, 0x2, 0x2, 0x2, 0x76, 0x77, 0x3, 0x2, 0x2, 0x2, 0x77, 0x78, 0x3,
- 0x2, 0x2, 0x2, 0x78, 0x7a, 0x5, 0x1c, 0xf, 0x2, 0x79, 0x74, 0x3,
- 0x2, 0x2, 0x2, 0x7a, 0x7d, 0x3, 0x2, 0x2, 0x2, 0x7b, 0x7c, 0x3, 0x2,
- 0x2, 0x2, 0x7b, 0x79, 0x3, 0x2, 0x2, 0x2, 0x7c, 0x7f, 0x3, 0x2, 0x2,
- 0x2, 0x7d, 0x7b, 0x3, 0x2, 0x2, 0x2, 0x7e, 0x80, 0x7, 0xd, 0x2, 0x2,
- 0x7f, 0x7e, 0x3, 0x2, 0x2, 0x2, 0x7f, 0x80, 0x3, 0x2, 0x2, 0x2, 0x80,
- 0x82, 0x3, 0x2, 0x2, 0x2, 0x81, 0x83, 0x5, 0x22, 0x12, 0x2, 0x82,
- 0x81, 0x3, 0x2, 0x2, 0x2, 0x82, 0x83, 0x3, 0x2, 0x2, 0x2, 0x83, 0x84,
- 0x3, 0x2, 0x2, 0x2, 0x84, 0x85, 0x7, 0x8, 0x2, 0x2, 0x85, 0x1b, 0x3,
- 0x2, 0x2, 0x2, 0x86, 0x89, 0x5, 0x1e, 0x10, 0x2, 0x87, 0x89, 0x5,
- 0x20, 0x11, 0x2, 0x88, 0x86, 0x3, 0x2, 0x2, 0x2, 0x88, 0x87, 0x3,
- 0x2, 0x2, 0x2, 0x89, 0x1d, 0x3, 0x2, 0x2, 0x2, 0x8a, 0x8c, 0x7, 0xf,
- 0x2, 0x2, 0x8b, 0x8d, 0x7, 0xe, 0x2, 0x2, 0x8c, 0x8b, 0x3, 0x2, 0x2,
+ 0x9, 0x11, 0x4, 0x12, 0x9, 0x12, 0x4, 0x13, 0x9, 0x13, 0x4, 0x14,
+ 0x9, 0x14, 0x3, 0x2, 0x3, 0x2, 0x7, 0x2, 0x2b, 0xa, 0x2, 0xc, 0x2,
+ 0xe, 0x2, 0x2e, 0xb, 0x2, 0x3, 0x2, 0x3, 0x2, 0x3, 0x3, 0x3, 0x3,
+ 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x5, 0x4, 0x37, 0xa, 0x4, 0x3, 0x4,
+ 0x3, 0x4, 0x3, 0x5, 0x3, 0x5, 0x3, 0x5, 0x3, 0x5, 0x3, 0x5, 0x3,
+ 0x5, 0x6, 0x5, 0x41, 0xa, 0x5, 0xd, 0x5, 0xe, 0x5, 0x42, 0x3, 0x6,
+ 0x3, 0x6, 0x3, 0x6, 0x6, 0x6, 0x48, 0xa, 0x6, 0xd, 0x6, 0xe, 0x6,
+ 0x49, 0x3, 0x7, 0x3, 0x7, 0x3, 0x7, 0x3, 0x7, 0x3, 0x7, 0x3, 0x7,
+ 0x5, 0x7, 0x52, 0xa, 0x7, 0x3, 0x7, 0x3, 0x7, 0x3, 0x7, 0x3, 0x7,
+ 0x3, 0x7, 0x3, 0x7, 0x7, 0x7, 0x5a, 0xa, 0x7, 0xc, 0x7, 0xe, 0x7,
+ 0x5d, 0xb, 0x7, 0x3, 0x8, 0x3, 0x8, 0x3, 0x8, 0x3, 0x8, 0x3, 0x8,
+ 0x3, 0x8, 0x3, 0x8, 0x3, 0x8, 0x3, 0x9, 0x3, 0x9, 0x3, 0x9, 0x3,
+ 0x9, 0x3, 0x9, 0x3, 0x9, 0x3, 0xa, 0x3, 0xa, 0x3, 0xa, 0x3, 0xa,
+ 0x3, 0xb, 0x3, 0xb, 0x3, 0xc, 0x5, 0xc, 0x74, 0xa, 0xc, 0x3, 0xc,
+ 0x3, 0xc, 0x5, 0xc, 0x78, 0xa, 0xc, 0x3, 0xd, 0x3, 0xd, 0x5, 0xd,
+ 0x7c, 0xa, 0xd, 0x3, 0xe, 0x3, 0xe, 0x3, 0xe, 0x5, 0xe, 0x81, 0xa,
+ 0xe, 0x3, 0xf, 0x3, 0xf, 0x3, 0xf, 0x5, 0xf, 0x86, 0xa, 0xf, 0x3,
+ 0xf, 0x5, 0xf, 0x89, 0xa, 0xf, 0x3, 0x10, 0x3, 0x10, 0x5, 0x10, 0x8d,
+ 0xa, 0x10, 0x3, 0x10, 0x3, 0x10, 0x3, 0x10, 0x5, 0x10, 0x92, 0xa,
+ 0x10, 0x3, 0x10, 0x7, 0x10, 0x95, 0xa, 0x10, 0xc, 0x10, 0xe, 0x10,
+ 0x98, 0xb, 0x10, 0x3, 0x10, 0x5, 0x10, 0x9b, 0xa, 0x10, 0x3, 0x10,
+ 0x5, 0x10, 0x9e, 0xa, 0x10, 0x3, 0x10, 0x3, 0x10, 0x3, 0x11, 0x3,
+ 0x11, 0x5, 0x11, 0xa4, 0xa, 0x11, 0x3, 0x12, 0x3, 0x12, 0x5, 0x12,
+ 0xa8, 0xa, 0x12, 0x3, 0x12, 0x3, 0x12, 0x5, 0x12, 0xac, 0xa, 0x12,
+ 0x3, 0x12, 0x3, 0x12, 0x3, 0x13, 0x3, 0x13, 0x3, 0x14, 0x6, 0x14,
+ 0xb3, 0xa, 0x14, 0xd, 0x14, 0xe, 0x14, 0xb4, 0x3, 0x14, 0x3, 0x96,
+ 0x2, 0x15, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, 0x12, 0x14, 0x16,
+ 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x2, 0x4, 0x3, 0x2,
+ 0xe, 0xf, 0x4, 0x2, 0xc, 0xc, 0xe, 0xe, 0x2, 0xc8, 0x2, 0x28, 0x3,
+ 0x2, 0x2, 0x2, 0x4, 0x31, 0x3, 0x2, 0x2, 0x2, 0x6, 0x36, 0x3, 0x2,
+ 0x2, 0x2, 0x8, 0x40, 0x3, 0x2, 0x2, 0x2, 0xa, 0x47, 0x3, 0x2, 0x2,
+ 0x2, 0xc, 0x51, 0x3, 0x2, 0x2, 0x2, 0xe, 0x5e, 0x3, 0x2, 0x2, 0x2,
+ 0x10, 0x66, 0x3, 0x2, 0x2, 0x2, 0x12, 0x6c, 0x3, 0x2, 0x2, 0x2, 0x14,
+ 0x70, 0x3, 0x2, 0x2, 0x2, 0x16, 0x73, 0x3, 0x2, 0x2, 0x2, 0x18, 0x79,
+ 0x3, 0x2, 0x2, 0x2, 0x1a, 0x7d, 0x3, 0x2, 0x2, 0x2, 0x1c, 0x82, 0x3,
+ 0x2, 0x2, 0x2, 0x1e, 0x8a, 0x3, 0x2, 0x2, 0x2, 0x20, 0xa3, 0x3, 0x2,
+ 0x2, 0x2, 0x22, 0xa5, 0x3, 0x2, 0x2, 0x2, 0x24, 0xaf, 0x3, 0x2, 0x2,
+ 0x2, 0x26, 0xb2, 0x3, 0x2, 0x2, 0x2, 0x28, 0x2c, 0x5, 0x4, 0x3, 0x2,
+ 0x29, 0x2b, 0x5, 0x6, 0x4, 0x2, 0x2a, 0x29, 0x3, 0x2, 0x2, 0x2, 0x2b,
+ 0x2e, 0x3, 0x2, 0x2, 0x2, 0x2c, 0x2a, 0x3, 0x2, 0x2, 0x2, 0x2c, 0x2d,
+ 0x3, 0x2, 0x2, 0x2, 0x2d, 0x2f, 0x3, 0x2, 0x2, 0x2, 0x2e, 0x2c, 0x3,
+ 0x2, 0x2, 0x2, 0x2f, 0x30, 0x7, 0x2, 0x2, 0x3, 0x30, 0x3, 0x3, 0x2,
+ 0x2, 0x2, 0x31, 0x32, 0x7, 0xb, 0x2, 0x2, 0x32, 0x33, 0x5, 0x1e,
+ 0x10, 0x2, 0x33, 0x34, 0x7, 0xc, 0x2, 0x2, 0x34, 0x5, 0x3, 0x2, 0x2,
+ 0x2, 0x35, 0x37, 0x5, 0x8, 0x5, 0x2, 0x36, 0x35, 0x3, 0x2, 0x2, 0x2,
+ 0x36, 0x37, 0x3, 0x2, 0x2, 0x2, 0x37, 0x38, 0x3, 0x2, 0x2, 0x2, 0x38,
+ 0x39, 0x7, 0xc, 0x2, 0x2, 0x39, 0x7, 0x3, 0x2, 0x2, 0x2, 0x3a, 0x41,
+ 0x5, 0x14, 0xb, 0x2, 0x3b, 0x41, 0x5, 0x1a, 0xe, 0x2, 0x3c, 0x41,
+ 0x5, 0x1c, 0xf, 0x2, 0x3d, 0x41, 0x5, 0x12, 0xa, 0x2, 0x3e, 0x41,
+ 0x5, 0x10, 0x9, 0x2, 0x3f, 0x41, 0x5, 0xe, 0x8, 0x2, 0x40, 0x3a,
+ 0x3, 0x2, 0x2, 0x2, 0x40, 0x3b, 0x3, 0x2, 0x2, 0x2, 0x40, 0x3c, 0x3,
+ 0x2, 0x2, 0x2, 0x40, 0x3d, 0x3, 0x2, 0x2, 0x2, 0x40, 0x3e, 0x3, 0x2,
+ 0x2, 0x2, 0x40, 0x3f, 0x3, 0x2, 0x2, 0x2, 0x41, 0x42, 0x3, 0x2, 0x2,
+ 0x2, 0x42, 0x40, 0x3, 0x2, 0x2, 0x2, 0x42, 0x43, 0x3, 0x2, 0x2, 0x2,
+ 0x43, 0x9, 0x3, 0x2, 0x2, 0x2, 0x44, 0x48, 0x5, 0x16, 0xc, 0x2, 0x45,
+ 0x48, 0x5, 0x1a, 0xe, 0x2, 0x46, 0x48, 0x5, 0x1c, 0xf, 0x2, 0x47,
+ 0x44, 0x3, 0x2, 0x2, 0x2, 0x47, 0x45, 0x3, 0x2, 0x2, 0x2, 0x47, 0x46,
+ 0x3, 0x2, 0x2, 0x2, 0x48, 0x49, 0x3, 0x2, 0x2, 0x2, 0x49, 0x47, 0x3,
+ 0x2, 0x2, 0x2, 0x49, 0x4a, 0x3, 0x2, 0x2, 0x2, 0x4a, 0xb, 0x3, 0x2,
+ 0x2, 0x2, 0x4b, 0x52, 0x5, 0x18, 0xd, 0x2, 0x4c, 0x52, 0x5, 0x1a,
+ 0xe, 0x2, 0x4d, 0x52, 0x5, 0x1c, 0xf, 0x2, 0x4e, 0x52, 0x5, 0x12,
+ 0xa, 0x2, 0x4f, 0x52, 0x5, 0x10, 0x9, 0x2, 0x50, 0x52, 0x5, 0xe,
+ 0x8, 0x2, 0x51, 0x4b, 0x3, 0x2, 0x2, 0x2, 0x51, 0x4c, 0x3, 0x2, 0x2,
+ 0x2, 0x51, 0x4d, 0x3, 0x2, 0x2, 0x2, 0x51, 0x4e, 0x3, 0x2, 0x2, 0x2,
+ 0x51, 0x4f, 0x3, 0x2, 0x2, 0x2, 0x51, 0x50, 0x3, 0x2, 0x2, 0x2, 0x52,
+ 0x5b, 0x3, 0x2, 0x2, 0x2, 0x53, 0x5a, 0x5, 0x14, 0xb, 0x2, 0x54,
+ 0x5a, 0x5, 0x1a, 0xe, 0x2, 0x55, 0x5a, 0x5, 0x1c, 0xf, 0x2, 0x56,
+ 0x5a, 0x5, 0x12, 0xa, 0x2, 0x57, 0x5a, 0x5, 0x10, 0x9, 0x2, 0x58,
+ 0x5a, 0x5, 0xe, 0x8, 0x2, 0x59, 0x53, 0x3, 0x2, 0x2, 0x2, 0x59, 0x54,
+ 0x3, 0x2, 0x2, 0x2, 0x59, 0x55, 0x3, 0x2, 0x2, 0x2, 0x59, 0x56, 0x3,
+ 0x2, 0x2, 0x2, 0x59, 0x57, 0x3, 0x2, 0x2, 0x2, 0x59, 0x58, 0x3, 0x2,
+ 0x2, 0x2, 0x5a, 0x5d, 0x3, 0x2, 0x2, 0x2, 0x5b, 0x59, 0x3, 0x2, 0x2,
+ 0x2, 0x5b, 0x5c, 0x3, 0x2, 0x2, 0x2, 0x5c, 0xd, 0x3, 0x2, 0x2, 0x2,
+ 0x5d, 0x5b, 0x3, 0x2, 0x2, 0x2, 0x5e, 0x5f, 0x7, 0x4, 0x2, 0x2, 0x5f,
+ 0x60, 0x7, 0x4, 0x2, 0x2, 0x60, 0x61, 0x7, 0x4, 0x2, 0x2, 0x61, 0x62,
+ 0x5, 0xa, 0x6, 0x2, 0x62, 0x63, 0x7, 0x4, 0x2, 0x2, 0x63, 0x64, 0x7,
+ 0x4, 0x2, 0x2, 0x64, 0x65, 0x7, 0x4, 0x2, 0x2, 0x65, 0xf, 0x3, 0x2,
+ 0x2, 0x2, 0x66, 0x67, 0x7, 0x4, 0x2, 0x2, 0x67, 0x68, 0x7, 0x4, 0x2,
+ 0x2, 0x68, 0x69, 0x5, 0xa, 0x6, 0x2, 0x69, 0x6a, 0x7, 0x4, 0x2, 0x2,
+ 0x6a, 0x6b, 0x7, 0x4, 0x2, 0x2, 0x6b, 0x11, 0x3, 0x2, 0x2, 0x2, 0x6c,
+ 0x6d, 0x7, 0x4, 0x2, 0x2, 0x6d, 0x6e, 0x5, 0xa, 0x6, 0x2, 0x6e, 0x6f,
+ 0x7, 0x4, 0x2, 0x2, 0x6f, 0x13, 0x3, 0x2, 0x2, 0x2, 0x70, 0x71, 0x9,
+ 0x2, 0x2, 0x2, 0x71, 0x15, 0x3, 0x2, 0x2, 0x2, 0x72, 0x74, 0x7, 0xe,
+ 0x2, 0x2, 0x73, 0x72, 0x3, 0x2, 0x2, 0x2, 0x73, 0x74, 0x3, 0x2, 0x2,
+ 0x2, 0x74, 0x75, 0x3, 0x2, 0x2, 0x2, 0x75, 0x77, 0x7, 0xf, 0x2, 0x2,
+ 0x76, 0x78, 0x7, 0xe, 0x2, 0x2, 0x77, 0x76, 0x3, 0x2, 0x2, 0x2, 0x77,
+ 0x78, 0x3, 0x2, 0x2, 0x2, 0x78, 0x17, 0x3, 0x2, 0x2, 0x2, 0x79, 0x7b,
+ 0x7, 0xf, 0x2, 0x2, 0x7a, 0x7c, 0x7, 0xe, 0x2, 0x2, 0x7b, 0x7a, 0x3,
+ 0x2, 0x2, 0x2, 0x7b, 0x7c, 0x3, 0x2, 0x2, 0x2, 0x7c, 0x19, 0x3, 0x2,
+ 0x2, 0x2, 0x7d, 0x7e, 0x7, 0x5, 0x2, 0x2, 0x7e, 0x80, 0x7, 0xf, 0x2,
+ 0x2, 0x7f, 0x81, 0x7, 0x7, 0x2, 0x2, 0x80, 0x7f, 0x3, 0x2, 0x2, 0x2,
+ 0x80, 0x81, 0x3, 0x2, 0x2, 0x2, 0x81, 0x1b, 0x3, 0x2, 0x2, 0x2, 0x82,
+ 0x83, 0x7, 0x6, 0x2, 0x2, 0x83, 0x85, 0x7, 0xf, 0x2, 0x2, 0x84, 0x86,
+ 0x5, 0x1e, 0x10, 0x2, 0x85, 0x84, 0x3, 0x2, 0x2, 0x2, 0x85, 0x86,
+ 0x3, 0x2, 0x2, 0x2, 0x86, 0x88, 0x3, 0x2, 0x2, 0x2, 0x87, 0x89, 0x7,
+ 0x7, 0x2, 0x2, 0x88, 0x87, 0x3, 0x2, 0x2, 0x2, 0x88, 0x89, 0x3, 0x2,
+ 0x2, 0x2, 0x89, 0x1d, 0x3, 0x2, 0x2, 0x2, 0x8a, 0x8c, 0x7, 0x9, 0x2,
+ 0x2, 0x8b, 0x8d, 0x5, 0x26, 0x14, 0x2, 0x8c, 0x8b, 0x3, 0x2, 0x2,
0x2, 0x8c, 0x8d, 0x3, 0x2, 0x2, 0x2, 0x8d, 0x8e, 0x3, 0x2, 0x2, 0x2,
- 0x8e, 0x90, 0x7, 0xa, 0x2, 0x2, 0x8f, 0x91, 0x7, 0xe, 0x2, 0x2, 0x90,
- 0x8f, 0x3, 0x2, 0x2, 0x2, 0x90, 0x91, 0x3, 0x2, 0x2, 0x2, 0x91, 0x92,
- 0x3, 0x2, 0x2, 0x2, 0x92, 0x93, 0x5, 0x8, 0x5, 0x2, 0x93, 0x1f, 0x3,
- 0x2, 0x2, 0x2, 0x94, 0x95, 0x5, 0x8, 0x5, 0x2, 0x95, 0x21, 0x3, 0x2,
- 0x2, 0x2, 0x96, 0x98, 0x9, 0x3, 0x2, 0x2, 0x97, 0x96, 0x3, 0x2, 0x2,
- 0x2, 0x98, 0x99, 0x3, 0x2, 0x2, 0x2, 0x99, 0x97, 0x3, 0x2, 0x2, 0x2,
- 0x99, 0x9a, 0x3, 0x2, 0x2, 0x2, 0x9a, 0x23, 0x3, 0x2, 0x2, 0x2, 0x16,
- 0x28, 0x32, 0x3c, 0x3e, 0x43, 0x45, 0x5c, 0x60, 0x65, 0x6a, 0x6d,
- 0x71, 0x76, 0x7b, 0x7f, 0x82, 0x88, 0x8c, 0x90, 0x99,
+ 0x8e, 0x96, 0x5, 0x20, 0x11, 0x2, 0x8f, 0x91, 0x7, 0xd, 0x2, 0x2,
+ 0x90, 0x92, 0x5, 0x26, 0x14, 0x2, 0x91, 0x90, 0x3, 0x2, 0x2, 0x2,
+ 0x91, 0x92, 0x3, 0x2, 0x2, 0x2, 0x92, 0x93, 0x3, 0x2, 0x2, 0x2, 0x93,
+ 0x95, 0x5, 0x20, 0x11, 0x2, 0x94, 0x8f, 0x3, 0x2, 0x2, 0x2, 0x95,
+ 0x98, 0x3, 0x2, 0x2, 0x2, 0x96, 0x97, 0x3, 0x2, 0x2, 0x2, 0x96, 0x94,
+ 0x3, 0x2, 0x2, 0x2, 0x97, 0x9a, 0x3, 0x2, 0x2, 0x2, 0x98, 0x96, 0x3,
+ 0x2, 0x2, 0x2, 0x99, 0x9b, 0x7, 0xd, 0x2, 0x2, 0x9a, 0x99, 0x3, 0x2,
+ 0x2, 0x2, 0x9a, 0x9b, 0x3, 0x2, 0x2, 0x2, 0x9b, 0x9d, 0x3, 0x2, 0x2,
+ 0x2, 0x9c, 0x9e, 0x5, 0x26, 0x14, 0x2, 0x9d, 0x9c, 0x3, 0x2, 0x2,
+ 0x2, 0x9d, 0x9e, 0x3, 0x2, 0x2, 0x2, 0x9e, 0x9f, 0x3, 0x2, 0x2, 0x2,
+ 0x9f, 0xa0, 0x7, 0x8, 0x2, 0x2, 0xa0, 0x1f, 0x3, 0x2, 0x2, 0x2, 0xa1,
+ 0xa4, 0x5, 0x22, 0x12, 0x2, 0xa2, 0xa4, 0x5, 0x24, 0x13, 0x2, 0xa3,
+ 0xa1, 0x3, 0x2, 0x2, 0x2, 0xa3, 0xa2, 0x3, 0x2, 0x2, 0x2, 0xa4, 0x21,
+ 0x3, 0x2, 0x2, 0x2, 0xa5, 0xa7, 0x7, 0xf, 0x2, 0x2, 0xa6, 0xa8, 0x7,
+ 0xe, 0x2, 0x2, 0xa7, 0xa6, 0x3, 0x2, 0x2, 0x2, 0xa7, 0xa8, 0x3, 0x2,
+ 0x2, 0x2, 0xa8, 0xa9, 0x3, 0x2, 0x2, 0x2, 0xa9, 0xab, 0x7, 0xa, 0x2,
+ 0x2, 0xaa, 0xac, 0x7, 0xe, 0x2, 0x2, 0xab, 0xaa, 0x3, 0x2, 0x2, 0x2,
+ 0xab, 0xac, 0x3, 0x2, 0x2, 0x2, 0xac, 0xad, 0x3, 0x2, 0x2, 0x2, 0xad,
+ 0xae, 0x5, 0xc, 0x7, 0x2, 0xae, 0x23, 0x3, 0x2, 0x2, 0x2, 0xaf, 0xb0,
+ 0x5, 0xc, 0x7, 0x2, 0xb0, 0x25, 0x3, 0x2, 0x2, 0x2, 0xb1, 0xb3, 0x9,
+ 0x3, 0x2, 0x2, 0xb2, 0xb1, 0x3, 0x2, 0x2, 0x2, 0xb3, 0xb4, 0x3, 0x2,
+ 0x2, 0x2, 0xb4, 0xb2, 0x3, 0x2, 0x2, 0x2, 0xb4, 0xb5, 0x3, 0x2, 0x2,
+ 0x2, 0xb5, 0x27, 0x3, 0x2, 0x2, 0x2, 0x1a, 0x2c, 0x36, 0x40, 0x42,
+ 0x47, 0x49, 0x51, 0x59, 0x5b, 0x73, 0x77, 0x7b, 0x80, 0x85, 0x88,
+ 0x8c, 0x91, 0x96, 0x9a, 0x9d, 0xa3, 0xa7, 0xab, 0xb4,
};
_serializedATN.insert(_serializedATN.end(), serializedATNSegment0,
diff --git a/src/grammar/cpp/zoiaParser.h b/src/grammar/cpp/zoiaParser.h
index fcd710c..5dd7a78 100644
--- a/src/grammar/cpp/zoiaParser.h
+++ b/src/grammar/cpp/zoiaParser.h
@@ -19,10 +19,11 @@ class zoiaParser : public antlr4::Parser {
enum {
RuleZoiaFile = 0, RuleHeader = 1, RuleLine = 2, RuleLineElements = 3,
- RuleLineElementsInner = 4, RuleEm3LineElement = 5, RuleEm2LineElement = 6,
- RuleEm1LineElement = 7, RuleTextFragment = 8, RuleTextFragmentReq = 9,
- RuleAlias = 10, RuleCommand = 11, RuleArguments = 12, RuleArgument = 13,
- RuleKwdArgument = 14, RuleStdArgument = 15, RuleWhitespace = 16
+ RuleLineElementsInner = 4, RuleLineElementsArg = 5, RuleEm3LineElement = 6,
+ RuleEm2LineElement = 7, RuleEm1LineElement = 8, RuleTextFragment = 9,
+ RuleTextFragmentReq = 10, RuleTextFragmentWord = 11, RuleAlias = 12,
+ RuleCommand = 13, RuleArguments = 14, RuleArgument = 15, RuleKwdArgument = 16,
+ RuleStdArgument = 17, RuleWhitespace = 18
};
explicit zoiaParser(antlr4::TokenStream *input);
@@ -40,11 +41,13 @@ class zoiaParser : public antlr4::Parser {
class LineContext;
class LineElementsContext;
class LineElementsInnerContext;
+ class LineElementsArgContext;
class Em3LineElementContext;
class Em2LineElementContext;
class Em1LineElementContext;
class TextFragmentContext;
class TextFragmentReqContext;
+ class TextFragmentWordContext;
class AliasContext;
class CommandContext;
class ArgumentsContext;
@@ -140,6 +143,31 @@ class zoiaParser : public antlr4::Parser {
LineElementsInnerContext* lineElementsInner();
+ class LineElementsArgContext : public antlr4::ParserRuleContext {
+ public:
+ LineElementsArgContext(antlr4::ParserRuleContext *parent, size_t invokingState);
+ virtual size_t getRuleIndex() const override;
+ TextFragmentWordContext *textFragmentWord();
+ std::vector alias();
+ AliasContext* alias(size_t i);
+ std::vector command();
+ CommandContext* command(size_t i);
+ std::vector em1LineElement();
+ Em1LineElementContext* em1LineElement(size_t i);
+ std::vector em2LineElement();
+ Em2LineElementContext* em2LineElement(size_t i);
+ std::vector em3LineElement();
+ Em3LineElementContext* em3LineElement(size_t i);
+ std::vector textFragment();
+ TextFragmentContext* textFragment(size_t i);
+
+
+ virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
+
+ };
+
+ LineElementsArgContext* lineElementsArg();
+
class Em3LineElementContext : public antlr4::ParserRuleContext {
public:
Em3LineElementContext(antlr4::ParserRuleContext *parent, size_t invokingState);
@@ -214,6 +242,20 @@ class zoiaParser : public antlr4::Parser {
TextFragmentReqContext* textFragmentReq();
+ class TextFragmentWordContext : public antlr4::ParserRuleContext {
+ public:
+ TextFragmentWordContext(antlr4::ParserRuleContext *parent, size_t invokingState);
+ virtual size_t getRuleIndex() const override;
+ antlr4::tree::TerminalNode *Word();
+ antlr4::tree::TerminalNode *Spaces();
+
+
+ virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
+
+ };
+
+ TextFragmentWordContext* textFragmentWord();
+
class AliasContext : public antlr4::ParserRuleContext {
public:
AliasContext(antlr4::ParserRuleContext *parent, size_t invokingState);
@@ -285,7 +327,7 @@ class zoiaParser : public antlr4::Parser {
virtual size_t getRuleIndex() const override;
antlr4::tree::TerminalNode *Word();
antlr4::tree::TerminalNode *Equals();
- LineElementsContext *lineElements();
+ LineElementsArgContext *lineElementsArg();
std::vector Spaces();
antlr4::tree::TerminalNode* Spaces(size_t i);
@@ -300,7 +342,7 @@ class zoiaParser : public antlr4::Parser {
public:
StdArgumentContext(antlr4::ParserRuleContext *parent, size_t invokingState);
virtual size_t getRuleIndex() const override;
- LineElementsContext *lineElements();
+ LineElementsArgContext *lineElementsArg();
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
diff --git a/src/grammar/cpp/zoiaVisitor.h b/src/grammar/cpp/zoiaVisitor.h
index da10630..79e25fb 100644
--- a/src/grammar/cpp/zoiaVisitor.h
+++ b/src/grammar/cpp/zoiaVisitor.h
@@ -29,6 +29,8 @@ class zoiaVisitor : public antlr4::tree::AbstractParseTreeVisitor {
virtual antlrcpp::Any visitLineElementsInner(zoiaParser::LineElementsInnerContext *context) = 0;
+ virtual antlrcpp::Any visitLineElementsArg(zoiaParser::LineElementsArgContext *context) = 0;
+
virtual antlrcpp::Any visitEm3LineElement(zoiaParser::Em3LineElementContext *context) = 0;
virtual antlrcpp::Any visitEm2LineElement(zoiaParser::Em2LineElementContext *context) = 0;
@@ -39,6 +41,8 @@ class zoiaVisitor : public antlr4::tree::AbstractParseTreeVisitor {
virtual antlrcpp::Any visitTextFragmentReq(zoiaParser::TextFragmentReqContext *context) = 0;
+ virtual antlrcpp::Any visitTextFragmentWord(zoiaParser::TextFragmentWordContext *context) = 0;
+
virtual antlrcpp::Any visitAlias(zoiaParser::AliasContext *context) = 0;
virtual antlrcpp::Any visitCommand(zoiaParser::CommandContext *context) = 0;
diff --git a/src/grammar/zoiaParser.py b/src/grammar/zoiaParser.py
index 6283964..d16b11d 100644
--- a/src/grammar/zoiaParser.py
+++ b/src/grammar/zoiaParser.py
@@ -12,61 +12,78 @@
def serializedATN():
with StringIO() as buf:
buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\17")
- buf.write("\u009c\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7")
+ buf.write("\u00b7\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7")
buf.write("\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r\4\16")
- buf.write("\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\3\2\3\2")
- buf.write("\7\2\'\n\2\f\2\16\2*\13\2\3\2\3\2\3\3\3\3\3\3\3\3\3\4")
- buf.write("\5\4\63\n\4\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\5\6\5=\n\5\r")
- buf.write("\5\16\5>\3\6\3\6\3\6\6\6D\n\6\r\6\16\6E\3\7\3\7\3\7\3")
- buf.write("\7\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3\t")
- buf.write("\3\t\3\n\3\n\3\13\5\13]\n\13\3\13\3\13\5\13a\n\13\3\f")
- buf.write("\3\f\3\f\5\ff\n\f\3\r\3\r\3\r\5\rk\n\r\3\r\5\rn\n\r\3")
- buf.write("\16\3\16\5\16r\n\16\3\16\3\16\3\16\5\16w\n\16\3\16\7\16")
- buf.write("z\n\16\f\16\16\16}\13\16\3\16\5\16\u0080\n\16\3\16\5\16")
- buf.write("\u0083\n\16\3\16\3\16\3\17\3\17\5\17\u0089\n\17\3\20\3")
- buf.write("\20\5\20\u008d\n\20\3\20\3\20\5\20\u0091\n\20\3\20\3\20")
- buf.write("\3\21\3\21\3\22\6\22\u0098\n\22\r\22\16\22\u0099\3\22")
- buf.write("\3{\2\23\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"\2\4")
- buf.write("\3\2\16\17\4\2\f\f\16\16\2\u00a3\2$\3\2\2\2\4-\3\2\2\2")
- buf.write("\6\62\3\2\2\2\b<\3\2\2\2\nC\3\2\2\2\fG\3\2\2\2\16O\3\2")
- buf.write("\2\2\20U\3\2\2\2\22Y\3\2\2\2\24\\\3\2\2\2\26b\3\2\2\2")
- buf.write("\30g\3\2\2\2\32o\3\2\2\2\34\u0088\3\2\2\2\36\u008a\3\2")
- buf.write("\2\2 \u0094\3\2\2\2\"\u0097\3\2\2\2$(\5\4\3\2%\'\5\6\4")
- buf.write("\2&%\3\2\2\2\'*\3\2\2\2(&\3\2\2\2()\3\2\2\2)+\3\2\2\2")
- buf.write("*(\3\2\2\2+,\7\2\2\3,\3\3\2\2\2-.\7\13\2\2./\5\32\16\2")
- buf.write("/\60\7\f\2\2\60\5\3\2\2\2\61\63\5\b\5\2\62\61\3\2\2\2")
- buf.write("\62\63\3\2\2\2\63\64\3\2\2\2\64\65\7\f\2\2\65\7\3\2\2")
- buf.write("\2\66=\5\22\n\2\67=\5\26\f\28=\5\30\r\29=\5\20\t\2:=\5")
- buf.write("\16\b\2;=\5\f\7\2<\66\3\2\2\2<\67\3\2\2\2<8\3\2\2\2<9")
- buf.write("\3\2\2\2<:\3\2\2\2<;\3\2\2\2=>\3\2\2\2><\3\2\2\2>?\3\2")
- buf.write("\2\2?\t\3\2\2\2@D\5\24\13\2AD\5\26\f\2BD\5\30\r\2C@\3")
- buf.write("\2\2\2CA\3\2\2\2CB\3\2\2\2DE\3\2\2\2EC\3\2\2\2EF\3\2\2")
- buf.write("\2F\13\3\2\2\2GH\7\4\2\2HI\7\4\2\2IJ\7\4\2\2JK\5\n\6\2")
- buf.write("KL\7\4\2\2LM\7\4\2\2MN\7\4\2\2N\r\3\2\2\2OP\7\4\2\2PQ")
- buf.write("\7\4\2\2QR\5\n\6\2RS\7\4\2\2ST\7\4\2\2T\17\3\2\2\2UV\7")
- buf.write("\4\2\2VW\5\n\6\2WX\7\4\2\2X\21\3\2\2\2YZ\t\2\2\2Z\23\3")
- buf.write("\2\2\2[]\7\16\2\2\\[\3\2\2\2\\]\3\2\2\2]^\3\2\2\2^`\7")
- buf.write("\17\2\2_a\7\16\2\2`_\3\2\2\2`a\3\2\2\2a\25\3\2\2\2bc\7")
- buf.write("\5\2\2ce\7\17\2\2df\7\7\2\2ed\3\2\2\2ef\3\2\2\2f\27\3")
- buf.write("\2\2\2gh\7\6\2\2hj\7\17\2\2ik\5\32\16\2ji\3\2\2\2jk\3")
- buf.write("\2\2\2km\3\2\2\2ln\7\7\2\2ml\3\2\2\2mn\3\2\2\2n\31\3\2")
- buf.write("\2\2oq\7\t\2\2pr\5\"\22\2qp\3\2\2\2qr\3\2\2\2rs\3\2\2")
- buf.write("\2s{\5\34\17\2tv\7\r\2\2uw\5\"\22\2vu\3\2\2\2vw\3\2\2")
- buf.write("\2wx\3\2\2\2xz\5\34\17\2yt\3\2\2\2z}\3\2\2\2{|\3\2\2\2")
- buf.write("{y\3\2\2\2|\177\3\2\2\2}{\3\2\2\2~\u0080\7\r\2\2\177~")
- buf.write("\3\2\2\2\177\u0080\3\2\2\2\u0080\u0082\3\2\2\2\u0081\u0083")
- buf.write("\5\"\22\2\u0082\u0081\3\2\2\2\u0082\u0083\3\2\2\2\u0083")
- buf.write("\u0084\3\2\2\2\u0084\u0085\7\b\2\2\u0085\33\3\2\2\2\u0086")
- buf.write("\u0089\5\36\20\2\u0087\u0089\5 \21\2\u0088\u0086\3\2\2")
- buf.write("\2\u0088\u0087\3\2\2\2\u0089\35\3\2\2\2\u008a\u008c\7")
- buf.write("\17\2\2\u008b\u008d\7\16\2\2\u008c\u008b\3\2\2\2\u008c")
- buf.write("\u008d\3\2\2\2\u008d\u008e\3\2\2\2\u008e\u0090\7\n\2\2")
- buf.write("\u008f\u0091\7\16\2\2\u0090\u008f\3\2\2\2\u0090\u0091")
- buf.write("\3\2\2\2\u0091\u0092\3\2\2\2\u0092\u0093\5\b\5\2\u0093")
- buf.write("\37\3\2\2\2\u0094\u0095\5\b\5\2\u0095!\3\2\2\2\u0096\u0098")
- buf.write("\t\3\2\2\u0097\u0096\3\2\2\2\u0098\u0099\3\2\2\2\u0099")
- buf.write("\u0097\3\2\2\2\u0099\u009a\3\2\2\2\u009a#\3\2\2\2\26(")
- buf.write("\62<>CE\\`ejmqv{\177\u0082\u0088\u008c\u0090\u0099")
+ buf.write("\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23\t\23")
+ buf.write("\4\24\t\24\3\2\3\2\7\2+\n\2\f\2\16\2.\13\2\3\2\3\2\3\3")
+ buf.write("\3\3\3\3\3\3\3\4\5\4\67\n\4\3\4\3\4\3\5\3\5\3\5\3\5\3")
+ buf.write("\5\3\5\6\5A\n\5\r\5\16\5B\3\6\3\6\3\6\6\6H\n\6\r\6\16")
+ buf.write("\6I\3\7\3\7\3\7\3\7\3\7\3\7\5\7R\n\7\3\7\3\7\3\7\3\7\3")
+ buf.write("\7\3\7\7\7Z\n\7\f\7\16\7]\13\7\3\b\3\b\3\b\3\b\3\b\3\b")
+ buf.write("\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\13")
+ buf.write("\3\13\3\f\5\ft\n\f\3\f\3\f\5\fx\n\f\3\r\3\r\5\r|\n\r\3")
+ buf.write("\16\3\16\3\16\5\16\u0081\n\16\3\17\3\17\3\17\5\17\u0086")
+ buf.write("\n\17\3\17\5\17\u0089\n\17\3\20\3\20\5\20\u008d\n\20\3")
+ buf.write("\20\3\20\3\20\5\20\u0092\n\20\3\20\7\20\u0095\n\20\f\20")
+ buf.write("\16\20\u0098\13\20\3\20\5\20\u009b\n\20\3\20\5\20\u009e")
+ buf.write("\n\20\3\20\3\20\3\21\3\21\5\21\u00a4\n\21\3\22\3\22\5")
+ buf.write("\22\u00a8\n\22\3\22\3\22\5\22\u00ac\n\22\3\22\3\22\3\23")
+ buf.write("\3\23\3\24\6\24\u00b3\n\24\r\24\16\24\u00b4\3\24\3\u0096")
+ buf.write("\2\25\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&\2\4")
+ buf.write("\3\2\16\17\4\2\f\f\16\16\2\u00c8\2(\3\2\2\2\4\61\3\2\2")
+ buf.write("\2\6\66\3\2\2\2\b@\3\2\2\2\nG\3\2\2\2\fQ\3\2\2\2\16^\3")
+ buf.write("\2\2\2\20f\3\2\2\2\22l\3\2\2\2\24p\3\2\2\2\26s\3\2\2\2")
+ buf.write("\30y\3\2\2\2\32}\3\2\2\2\34\u0082\3\2\2\2\36\u008a\3\2")
+ buf.write("\2\2 \u00a3\3\2\2\2\"\u00a5\3\2\2\2$\u00af\3\2\2\2&\u00b2")
+ buf.write("\3\2\2\2(,\5\4\3\2)+\5\6\4\2*)\3\2\2\2+.\3\2\2\2,*\3\2")
+ buf.write("\2\2,-\3\2\2\2-/\3\2\2\2.,\3\2\2\2/\60\7\2\2\3\60\3\3")
+ buf.write("\2\2\2\61\62\7\13\2\2\62\63\5\36\20\2\63\64\7\f\2\2\64")
+ buf.write("\5\3\2\2\2\65\67\5\b\5\2\66\65\3\2\2\2\66\67\3\2\2\2\67")
+ buf.write("8\3\2\2\289\7\f\2\29\7\3\2\2\2:A\5\24\13\2;A\5\32\16\2")
+ buf.write("A\5\20\t\2?A\5\16\b\2@:\3\2\2")
+ buf.write("\2@;\3\2\2\2@<\3\2\2\2@=\3\2\2\2@>\3\2\2\2@?\3\2\2\2A")
+ buf.write("B\3\2\2\2B@\3\2\2\2BC\3\2\2\2C\t\3\2\2\2DH\5\26\f\2EH")
+ buf.write("\5\32\16\2FH\5\34\17\2GD\3\2\2\2GE\3\2\2\2GF\3\2\2\2H")
+ buf.write("I\3\2\2\2IG\3\2\2\2IJ\3\2\2\2J\13\3\2\2\2KR\5\30\r\2L")
+ buf.write("R\5\32\16\2MR\5\34\17\2NR\5\22\n\2OR\5\20\t\2PR\5\16\b")
+ buf.write("\2QK\3\2\2\2QL\3\2\2\2QM\3\2\2\2QN\3\2\2\2QO\3\2\2\2Q")
+ buf.write("P\3\2\2\2R[\3\2\2\2SZ\5\24\13\2TZ\5\32\16\2UZ\5\34\17")
+ buf.write("\2VZ\5\22\n\2WZ\5\20\t\2XZ\5\16\b\2YS\3\2\2\2YT\3\2\2")
+ buf.write("\2YU\3\2\2\2YV\3\2\2\2YW\3\2\2\2YX\3\2\2\2Z]\3\2\2\2[")
+ buf.write("Y\3\2\2\2[\\\3\2\2\2\\\r\3\2\2\2][\3\2\2\2^_\7\4\2\2_")
+ buf.write("`\7\4\2\2`a\7\4\2\2ab\5\n\6\2bc\7\4\2\2cd\7\4\2\2de\7")
+ buf.write("\4\2\2e\17\3\2\2\2fg\7\4\2\2gh\7\4\2\2hi\5\n\6\2ij\7\4")
+ buf.write("\2\2jk\7\4\2\2k\21\3\2\2\2lm\7\4\2\2mn\5\n\6\2no\7\4\2")
+ buf.write("\2o\23\3\2\2\2pq\t\2\2\2q\25\3\2\2\2rt\7\16\2\2sr\3\2")
+ buf.write("\2\2st\3\2\2\2tu\3\2\2\2uw\7\17\2\2vx\7\16\2\2wv\3\2\2")
+ buf.write("\2wx\3\2\2\2x\27\3\2\2\2y{\7\17\2\2z|\7\16\2\2{z\3\2\2")
+ buf.write("\2{|\3\2\2\2|\31\3\2\2\2}~\7\5\2\2~\u0080\7\17\2\2\177")
+ buf.write("\u0081\7\7\2\2\u0080\177\3\2\2\2\u0080\u0081\3\2\2\2\u0081")
+ buf.write("\33\3\2\2\2\u0082\u0083\7\6\2\2\u0083\u0085\7\17\2\2\u0084")
+ buf.write("\u0086\5\36\20\2\u0085\u0084\3\2\2\2\u0085\u0086\3\2\2")
+ buf.write("\2\u0086\u0088\3\2\2\2\u0087\u0089\7\7\2\2\u0088\u0087")
+ buf.write("\3\2\2\2\u0088\u0089\3\2\2\2\u0089\35\3\2\2\2\u008a\u008c")
+ buf.write("\7\t\2\2\u008b\u008d\5&\24\2\u008c\u008b\3\2\2\2\u008c")
+ buf.write("\u008d\3\2\2\2\u008d\u008e\3\2\2\2\u008e\u0096\5 \21\2")
+ buf.write("\u008f\u0091\7\r\2\2\u0090\u0092\5&\24\2\u0091\u0090\3")
+ buf.write("\2\2\2\u0091\u0092\3\2\2\2\u0092\u0093\3\2\2\2\u0093\u0095")
+ buf.write("\5 \21\2\u0094\u008f\3\2\2\2\u0095\u0098\3\2\2\2\u0096")
+ buf.write("\u0097\3\2\2\2\u0096\u0094\3\2\2\2\u0097\u009a\3\2\2\2")
+ buf.write("\u0098\u0096\3\2\2\2\u0099\u009b\7\r\2\2\u009a\u0099\3")
+ buf.write("\2\2\2\u009a\u009b\3\2\2\2\u009b\u009d\3\2\2\2\u009c\u009e")
+ buf.write("\5&\24\2\u009d\u009c\3\2\2\2\u009d\u009e\3\2\2\2\u009e")
+ buf.write("\u009f\3\2\2\2\u009f\u00a0\7\b\2\2\u00a0\37\3\2\2\2\u00a1")
+ buf.write("\u00a4\5\"\22\2\u00a2\u00a4\5$\23\2\u00a3\u00a1\3\2\2")
+ buf.write("\2\u00a3\u00a2\3\2\2\2\u00a4!\3\2\2\2\u00a5\u00a7\7\17")
+ buf.write("\2\2\u00a6\u00a8\7\16\2\2\u00a7\u00a6\3\2\2\2\u00a7\u00a8")
+ buf.write("\3\2\2\2\u00a8\u00a9\3\2\2\2\u00a9\u00ab\7\n\2\2\u00aa")
+ buf.write("\u00ac\7\16\2\2\u00ab\u00aa\3\2\2\2\u00ab\u00ac\3\2\2")
+ buf.write("\2\u00ac\u00ad\3\2\2\2\u00ad\u00ae\5\f\7\2\u00ae#\3\2")
+ buf.write("\2\2\u00af\u00b0\5\f\7\2\u00b0%\3\2\2\2\u00b1\u00b3\t")
+ buf.write("\3\2\2\u00b2\u00b1\3\2\2\2\u00b3\u00b4\3\2\2\2\u00b4\u00b2")
+ buf.write("\3\2\2\2\u00b4\u00b5\3\2\2\2\u00b5\'\3\2\2\2\32,\66@B")
+ buf.write("GIQY[sw{\u0080\u0085\u0088\u008c\u0091\u0096\u009a\u009d")
+ buf.write("\u00a3\u00a7\u00ab\u00b4")
return buf.getvalue()
@@ -92,24 +109,26 @@ class zoiaParser ( Parser ):
RULE_line = 2
RULE_lineElements = 3
RULE_lineElementsInner = 4
- RULE_em3LineElement = 5
- RULE_em2LineElement = 6
- RULE_em1LineElement = 7
- RULE_textFragment = 8
- RULE_textFragmentReq = 9
- RULE_alias = 10
- RULE_command = 11
- RULE_arguments = 12
- RULE_argument = 13
- RULE_kwdArgument = 14
- RULE_stdArgument = 15
- RULE_whitespace = 16
+ RULE_lineElementsArg = 5
+ RULE_em3LineElement = 6
+ RULE_em2LineElement = 7
+ RULE_em1LineElement = 8
+ RULE_textFragment = 9
+ RULE_textFragmentReq = 10
+ RULE_textFragmentWord = 11
+ RULE_alias = 12
+ RULE_command = 13
+ RULE_arguments = 14
+ RULE_argument = 15
+ RULE_kwdArgument = 16
+ RULE_stdArgument = 17
+ RULE_whitespace = 18
ruleNames = [ "zoiaFile", "header", "line", "lineElements", "lineElementsInner",
- "em3LineElement", "em2LineElement", "em1LineElement",
- "textFragment", "textFragmentReq", "alias", "command",
- "arguments", "argument", "kwdArgument", "stdArgument",
- "whitespace" ]
+ "lineElementsArg", "em3LineElement", "em2LineElement",
+ "em1LineElement", "textFragment", "textFragmentReq",
+ "textFragmentWord", "alias", "command", "arguments",
+ "argument", "kwdArgument", "stdArgument", "whitespace" ]
EOF = Token.EOF
COMMENT=1
@@ -175,19 +194,19 @@ def zoiaFile(self):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 34
- self.header()
self.state = 38
+ self.header()
+ self.state = 42
self._errHandler.sync(self)
_la = self._input.LA(1)
while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << zoiaParser.Asterisk) | (1 << zoiaParser.At) | (1 << zoiaParser.Backslash) | (1 << zoiaParser.Newline) | (1 << zoiaParser.Spaces) | (1 << zoiaParser.Word))) != 0):
- self.state = 35
+ self.state = 39
self.line()
- self.state = 40
+ self.state = 44
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 41
+ self.state = 45
self.match(zoiaParser.EOF)
except RecognitionException as re:
localctx.exception = re
@@ -233,11 +252,11 @@ def header(self):
self.enterRule(localctx, 2, self.RULE_header)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 43
+ self.state = 47
self.match(zoiaParser.Header)
- self.state = 44
+ self.state = 48
self.arguments()
- self.state = 45
+ self.state = 49
self.match(zoiaParser.Newline)
except RecognitionException as re:
localctx.exception = re
@@ -281,15 +300,15 @@ def line(self):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 48
+ self.state = 52
self._errHandler.sync(self)
_la = self._input.LA(1)
if (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << zoiaParser.Asterisk) | (1 << zoiaParser.At) | (1 << zoiaParser.Backslash) | (1 << zoiaParser.Spaces) | (1 << zoiaParser.Word))) != 0):
- self.state = 47
+ self.state = 51
self.lineElements()
- self.state = 50
+ self.state = 54
self.match(zoiaParser.Newline)
except RecognitionException as re:
localctx.exception = re
@@ -365,53 +384,52 @@ def lineElements(self):
localctx = zoiaParser.LineElementsContext(self, self._ctx, self.state)
self.enterRule(localctx, 6, self.RULE_lineElements)
+ self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 58
+ self.state = 62
self._errHandler.sync(self)
- _alt = 1
- while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER:
- if _alt == 1:
- self.state = 58
- self._errHandler.sync(self)
- la_ = self._interp.adaptivePredict(self._input,2,self._ctx)
- if la_ == 1:
- self.state = 52
- self.textFragment()
- pass
-
- elif la_ == 2:
- self.state = 53
- self.alias()
- pass
+ _la = self._input.LA(1)
+ while True:
+ self.state = 62
+ self._errHandler.sync(self)
+ la_ = self._interp.adaptivePredict(self._input,2,self._ctx)
+ if la_ == 1:
+ self.state = 56
+ self.textFragment()
+ pass
- elif la_ == 3:
- self.state = 54
- self.command()
- pass
+ elif la_ == 2:
+ self.state = 57
+ self.alias()
+ pass
- elif la_ == 4:
- self.state = 55
- self.em1LineElement()
- pass
+ elif la_ == 3:
+ self.state = 58
+ self.command()
+ pass
- elif la_ == 5:
- self.state = 56
- self.em2LineElement()
- pass
+ elif la_ == 4:
+ self.state = 59
+ self.em1LineElement()
+ pass
- elif la_ == 6:
- self.state = 57
- self.em3LineElement()
- pass
+ elif la_ == 5:
+ self.state = 60
+ self.em2LineElement()
+ pass
+ elif la_ == 6:
+ self.state = 61
+ self.em3LineElement()
+ pass
- else:
- raise NoViableAltException(self)
- self.state = 60
+ self.state = 64
self._errHandler.sync(self)
- _alt = self._interp.adaptivePredict(self._input,3,self._ctx)
+ _la = self._input.LA(1)
+ if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << zoiaParser.Asterisk) | (1 << zoiaParser.At) | (1 << zoiaParser.Backslash) | (1 << zoiaParser.Spaces) | (1 << zoiaParser.Word))) != 0)):
+ break
except RecognitionException as re:
localctx.exception = re
@@ -469,29 +487,29 @@ def lineElementsInner(self):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 65
+ self.state = 69
self._errHandler.sync(self)
_la = self._input.LA(1)
while True:
- self.state = 65
+ self.state = 69
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [zoiaParser.Spaces, zoiaParser.Word]:
- self.state = 62
+ self.state = 66
self.textFragmentReq()
pass
elif token in [zoiaParser.At]:
- self.state = 63
+ self.state = 67
self.alias()
pass
elif token in [zoiaParser.Backslash]:
- self.state = 64
+ self.state = 68
self.command()
pass
else:
raise NoViableAltException(self)
- self.state = 67
+ self.state = 71
self._errHandler.sync(self)
_la = self._input.LA(1)
if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << zoiaParser.At) | (1 << zoiaParser.Backslash) | (1 << zoiaParser.Spaces) | (1 << zoiaParser.Word))) != 0)):
@@ -506,6 +524,163 @@ def lineElementsInner(self):
return localctx
+ class LineElementsArgContext(ParserRuleContext):
+ __slots__ = 'parser'
+
+ def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1):
+ super().__init__(parent, invokingState)
+ self.parser = parser
+
+ def textFragmentWord(self):
+ return self.getTypedRuleContext(zoiaParser.TextFragmentWordContext,0)
+
+
+ def alias(self, i:int=None):
+ if i is None:
+ return self.getTypedRuleContexts(zoiaParser.AliasContext)
+ else:
+ return self.getTypedRuleContext(zoiaParser.AliasContext,i)
+
+
+ def command(self, i:int=None):
+ if i is None:
+ return self.getTypedRuleContexts(zoiaParser.CommandContext)
+ else:
+ return self.getTypedRuleContext(zoiaParser.CommandContext,i)
+
+
+ def em1LineElement(self, i:int=None):
+ if i is None:
+ return self.getTypedRuleContexts(zoiaParser.Em1LineElementContext)
+ else:
+ return self.getTypedRuleContext(zoiaParser.Em1LineElementContext,i)
+
+
+ def em2LineElement(self, i:int=None):
+ if i is None:
+ return self.getTypedRuleContexts(zoiaParser.Em2LineElementContext)
+ else:
+ return self.getTypedRuleContext(zoiaParser.Em2LineElementContext,i)
+
+
+ def em3LineElement(self, i:int=None):
+ if i is None:
+ return self.getTypedRuleContexts(zoiaParser.Em3LineElementContext)
+ else:
+ return self.getTypedRuleContext(zoiaParser.Em3LineElementContext,i)
+
+
+ def textFragment(self, i:int=None):
+ if i is None:
+ return self.getTypedRuleContexts(zoiaParser.TextFragmentContext)
+ else:
+ return self.getTypedRuleContext(zoiaParser.TextFragmentContext,i)
+
+
+ def getRuleIndex(self):
+ return zoiaParser.RULE_lineElementsArg
+
+ def accept(self, visitor:ParseTreeVisitor):
+ if hasattr( visitor, "visitLineElementsArg" ):
+ return visitor.visitLineElementsArg(self)
+ else:
+ return visitor.visitChildren(self)
+
+
+
+
+ def lineElementsArg(self):
+
+ localctx = zoiaParser.LineElementsArgContext(self, self._ctx, self.state)
+ self.enterRule(localctx, 10, self.RULE_lineElementsArg)
+ try:
+ self.enterOuterAlt(localctx, 1)
+ self.state = 79
+ self._errHandler.sync(self)
+ la_ = self._interp.adaptivePredict(self._input,6,self._ctx)
+ if la_ == 1:
+ self.state = 73
+ self.textFragmentWord()
+ pass
+
+ elif la_ == 2:
+ self.state = 74
+ self.alias()
+ pass
+
+ elif la_ == 3:
+ self.state = 75
+ self.command()
+ pass
+
+ elif la_ == 4:
+ self.state = 76
+ self.em1LineElement()
+ pass
+
+ elif la_ == 5:
+ self.state = 77
+ self.em2LineElement()
+ pass
+
+ elif la_ == 6:
+ self.state = 78
+ self.em3LineElement()
+ pass
+
+
+ self.state = 89
+ self._errHandler.sync(self)
+ _alt = self._interp.adaptivePredict(self._input,8,self._ctx)
+ while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER:
+ if _alt==1:
+ self.state = 87
+ self._errHandler.sync(self)
+ la_ = self._interp.adaptivePredict(self._input,7,self._ctx)
+ if la_ == 1:
+ self.state = 81
+ self.textFragment()
+ pass
+
+ elif la_ == 2:
+ self.state = 82
+ self.alias()
+ pass
+
+ elif la_ == 3:
+ self.state = 83
+ self.command()
+ pass
+
+ elif la_ == 4:
+ self.state = 84
+ self.em1LineElement()
+ pass
+
+ elif la_ == 5:
+ self.state = 85
+ self.em2LineElement()
+ pass
+
+ elif la_ == 6:
+ self.state = 86
+ self.em3LineElement()
+ pass
+
+
+ self.state = 91
+ self._errHandler.sync(self)
+ _alt = self._interp.adaptivePredict(self._input,8,self._ctx)
+
+ except RecognitionException as re:
+ localctx.exception = re
+ self._errHandler.reportError(self, re)
+ self._errHandler.recover(self, re)
+ finally:
+ self.exitRule()
+ return localctx
+
+
class Em3LineElementContext(ParserRuleContext):
__slots__ = 'parser'
@@ -538,22 +713,22 @@ def accept(self, visitor:ParseTreeVisitor):
def em3LineElement(self):
localctx = zoiaParser.Em3LineElementContext(self, self._ctx, self.state)
- self.enterRule(localctx, 10, self.RULE_em3LineElement)
+ self.enterRule(localctx, 12, self.RULE_em3LineElement)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 69
+ self.state = 92
self.match(zoiaParser.Asterisk)
- self.state = 70
+ self.state = 93
self.match(zoiaParser.Asterisk)
- self.state = 71
+ self.state = 94
self.match(zoiaParser.Asterisk)
- self.state = 72
+ self.state = 95
self.lineElementsInner()
- self.state = 73
+ self.state = 96
self.match(zoiaParser.Asterisk)
- self.state = 74
+ self.state = 97
self.match(zoiaParser.Asterisk)
- self.state = 75
+ self.state = 98
self.match(zoiaParser.Asterisk)
except RecognitionException as re:
localctx.exception = re
@@ -596,18 +771,18 @@ def accept(self, visitor:ParseTreeVisitor):
def em2LineElement(self):
localctx = zoiaParser.Em2LineElementContext(self, self._ctx, self.state)
- self.enterRule(localctx, 12, self.RULE_em2LineElement)
+ self.enterRule(localctx, 14, self.RULE_em2LineElement)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 77
+ self.state = 100
self.match(zoiaParser.Asterisk)
- self.state = 78
+ self.state = 101
self.match(zoiaParser.Asterisk)
- self.state = 79
+ self.state = 102
self.lineElementsInner()
- self.state = 80
+ self.state = 103
self.match(zoiaParser.Asterisk)
- self.state = 81
+ self.state = 104
self.match(zoiaParser.Asterisk)
except RecognitionException as re:
localctx.exception = re
@@ -650,14 +825,14 @@ def accept(self, visitor:ParseTreeVisitor):
def em1LineElement(self):
localctx = zoiaParser.Em1LineElementContext(self, self._ctx, self.state)
- self.enterRule(localctx, 14, self.RULE_em1LineElement)
+ self.enterRule(localctx, 16, self.RULE_em1LineElement)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 83
+ self.state = 106
self.match(zoiaParser.Asterisk)
- self.state = 84
+ self.state = 107
self.lineElementsInner()
- self.state = 85
+ self.state = 108
self.match(zoiaParser.Asterisk)
except RecognitionException as re:
localctx.exception = re
@@ -696,11 +871,11 @@ def accept(self, visitor:ParseTreeVisitor):
def textFragment(self):
localctx = zoiaParser.TextFragmentContext(self, self._ctx, self.state)
- self.enterRule(localctx, 16, self.RULE_textFragment)
+ self.enterRule(localctx, 18, self.RULE_textFragment)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 87
+ self.state = 110
_la = self._input.LA(1)
if not(_la==zoiaParser.Spaces or _la==zoiaParser.Word):
self._errHandler.recoverInline(self)
@@ -747,25 +922,75 @@ def accept(self, visitor:ParseTreeVisitor):
def textFragmentReq(self):
localctx = zoiaParser.TextFragmentReqContext(self, self._ctx, self.state)
- self.enterRule(localctx, 18, self.RULE_textFragmentReq)
+ self.enterRule(localctx, 20, self.RULE_textFragmentReq)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 90
+ self.state = 113
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==zoiaParser.Spaces:
- self.state = 89
+ self.state = 112
self.match(zoiaParser.Spaces)
- self.state = 92
+ self.state = 115
self.match(zoiaParser.Word)
- self.state = 94
+ self.state = 117
+ self._errHandler.sync(self)
+ la_ = self._interp.adaptivePredict(self._input,10,self._ctx)
+ if la_ == 1:
+ self.state = 116
+ self.match(zoiaParser.Spaces)
+
+
+ except RecognitionException as re:
+ localctx.exception = re
+ self._errHandler.reportError(self, re)
+ self._errHandler.recover(self, re)
+ finally:
+ self.exitRule()
+ return localctx
+
+
+ class TextFragmentWordContext(ParserRuleContext):
+ __slots__ = 'parser'
+
+ def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1):
+ super().__init__(parent, invokingState)
+ self.parser = parser
+
+ def Word(self):
+ return self.getToken(zoiaParser.Word, 0)
+
+ def Spaces(self):
+ return self.getToken(zoiaParser.Spaces, 0)
+
+ def getRuleIndex(self):
+ return zoiaParser.RULE_textFragmentWord
+
+ def accept(self, visitor:ParseTreeVisitor):
+ if hasattr( visitor, "visitTextFragmentWord" ):
+ return visitor.visitTextFragmentWord(self)
+ else:
+ return visitor.visitChildren(self)
+
+
+
+
+ def textFragmentWord(self):
+
+ localctx = zoiaParser.TextFragmentWordContext(self, self._ctx, self.state)
+ self.enterRule(localctx, 22, self.RULE_textFragmentWord)
+ try:
+ self.enterOuterAlt(localctx, 1)
+ self.state = 119
+ self.match(zoiaParser.Word)
+ self.state = 121
self._errHandler.sync(self)
- la_ = self._interp.adaptivePredict(self._input,7,self._ctx)
+ la_ = self._interp.adaptivePredict(self._input,11,self._ctx)
if la_ == 1:
- self.state = 93
+ self.state = 120
self.match(zoiaParser.Spaces)
@@ -809,19 +1034,19 @@ def accept(self, visitor:ParseTreeVisitor):
def alias(self):
localctx = zoiaParser.AliasContext(self, self._ctx, self.state)
- self.enterRule(localctx, 20, self.RULE_alias)
+ self.enterRule(localctx, 24, self.RULE_alias)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 96
+ self.state = 123
self.match(zoiaParser.At)
- self.state = 97
+ self.state = 124
self.match(zoiaParser.Word)
- self.state = 99
+ self.state = 126
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==zoiaParser.Bar:
- self.state = 98
+ self.state = 125
self.match(zoiaParser.Bar)
@@ -869,27 +1094,27 @@ def accept(self, visitor:ParseTreeVisitor):
def command(self):
localctx = zoiaParser.CommandContext(self, self._ctx, self.state)
- self.enterRule(localctx, 22, self.RULE_command)
+ self.enterRule(localctx, 26, self.RULE_command)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 101
+ self.state = 128
self.match(zoiaParser.Backslash)
- self.state = 102
+ self.state = 129
self.match(zoiaParser.Word)
- self.state = 104
+ self.state = 131
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==zoiaParser.BracketsOpen:
- self.state = 103
+ self.state = 130
self.arguments()
- self.state = 107
+ self.state = 134
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==zoiaParser.Bar:
- self.state = 106
+ self.state = 133
self.match(zoiaParser.Bar)
@@ -950,60 +1175,60 @@ def accept(self, visitor:ParseTreeVisitor):
def arguments(self):
localctx = zoiaParser.ArgumentsContext(self, self._ctx, self.state)
- self.enterRule(localctx, 24, self.RULE_arguments)
+ self.enterRule(localctx, 28, self.RULE_arguments)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 109
+ self.state = 136
self.match(zoiaParser.BracketsOpen)
- self.state = 111
+ self.state = 138
self._errHandler.sync(self)
- la_ = self._interp.adaptivePredict(self._input,11,self._ctx)
- if la_ == 1:
- self.state = 110
+ _la = self._input.LA(1)
+ if _la==zoiaParser.Newline or _la==zoiaParser.Spaces:
+ self.state = 137
self.whitespace()
- self.state = 113
+ self.state = 140
self.argument()
- self.state = 121
+ self.state = 148
self._errHandler.sync(self)
- _alt = self._interp.adaptivePredict(self._input,13,self._ctx)
+ _alt = self._interp.adaptivePredict(self._input,17,self._ctx)
while _alt!=1 and _alt!=ATN.INVALID_ALT_NUMBER:
if _alt==1+1:
- self.state = 114
+ self.state = 141
self.match(zoiaParser.Semicolon)
- self.state = 116
+ self.state = 143
self._errHandler.sync(self)
- la_ = self._interp.adaptivePredict(self._input,12,self._ctx)
- if la_ == 1:
- self.state = 115
+ _la = self._input.LA(1)
+ if _la==zoiaParser.Newline or _la==zoiaParser.Spaces:
+ self.state = 142
self.whitespace()
- self.state = 118
+ self.state = 145
self.argument()
- self.state = 123
+ self.state = 150
self._errHandler.sync(self)
- _alt = self._interp.adaptivePredict(self._input,13,self._ctx)
+ _alt = self._interp.adaptivePredict(self._input,17,self._ctx)
- self.state = 125
+ self.state = 152
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==zoiaParser.Semicolon:
- self.state = 124
+ self.state = 151
self.match(zoiaParser.Semicolon)
- self.state = 128
+ self.state = 155
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==zoiaParser.Newline or _la==zoiaParser.Spaces:
- self.state = 127
+ self.state = 154
self.whitespace()
- self.state = 130
+ self.state = 157
self.match(zoiaParser.BracketsClose)
except RecognitionException as re:
localctx.exception = re
@@ -1044,20 +1269,20 @@ def accept(self, visitor:ParseTreeVisitor):
def argument(self):
localctx = zoiaParser.ArgumentContext(self, self._ctx, self.state)
- self.enterRule(localctx, 26, self.RULE_argument)
+ self.enterRule(localctx, 30, self.RULE_argument)
try:
- self.state = 134
+ self.state = 161
self._errHandler.sync(self)
- la_ = self._interp.adaptivePredict(self._input,16,self._ctx)
+ la_ = self._interp.adaptivePredict(self._input,20,self._ctx)
if la_ == 1:
self.enterOuterAlt(localctx, 1)
- self.state = 132
+ self.state = 159
self.kwdArgument()
pass
elif la_ == 2:
self.enterOuterAlt(localctx, 2)
- self.state = 133
+ self.state = 160
self.stdArgument()
pass
@@ -1084,8 +1309,8 @@ def Word(self):
def Equals(self):
return self.getToken(zoiaParser.Equals, 0)
- def lineElements(self):
- return self.getTypedRuleContext(zoiaParser.LineElementsContext,0)
+ def lineElementsArg(self):
+ return self.getTypedRuleContext(zoiaParser.LineElementsArgContext,0)
def Spaces(self, i:int=None):
@@ -1109,32 +1334,32 @@ def accept(self, visitor:ParseTreeVisitor):
def kwdArgument(self):
localctx = zoiaParser.KwdArgumentContext(self, self._ctx, self.state)
- self.enterRule(localctx, 28, self.RULE_kwdArgument)
+ self.enterRule(localctx, 32, self.RULE_kwdArgument)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 136
+ self.state = 163
self.match(zoiaParser.Word)
- self.state = 138
+ self.state = 165
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==zoiaParser.Spaces:
- self.state = 137
+ self.state = 164
self.match(zoiaParser.Spaces)
- self.state = 140
+ self.state = 167
self.match(zoiaParser.Equals)
- self.state = 142
+ self.state = 169
self._errHandler.sync(self)
- la_ = self._interp.adaptivePredict(self._input,18,self._ctx)
- if la_ == 1:
- self.state = 141
+ _la = self._input.LA(1)
+ if _la==zoiaParser.Spaces:
+ self.state = 168
self.match(zoiaParser.Spaces)
- self.state = 144
- self.lineElements()
+ self.state = 171
+ self.lineElementsArg()
except RecognitionException as re:
localctx.exception = re
self._errHandler.reportError(self, re)
@@ -1151,8 +1376,8 @@ def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1):
super().__init__(parent, invokingState)
self.parser = parser
- def lineElements(self):
- return self.getTypedRuleContext(zoiaParser.LineElementsContext,0)
+ def lineElementsArg(self):
+ return self.getTypedRuleContext(zoiaParser.LineElementsArgContext,0)
def getRuleIndex(self):
@@ -1170,11 +1395,11 @@ def accept(self, visitor:ParseTreeVisitor):
def stdArgument(self):
localctx = zoiaParser.StdArgumentContext(self, self._ctx, self.state)
- self.enterRule(localctx, 30, self.RULE_stdArgument)
+ self.enterRule(localctx, 34, self.RULE_stdArgument)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 146
- self.lineElements()
+ self.state = 173
+ self.lineElementsArg()
except RecognitionException as re:
localctx.exception = re
self._errHandler.reportError(self, re)
@@ -1218,28 +1443,26 @@ def accept(self, visitor:ParseTreeVisitor):
def whitespace(self):
localctx = zoiaParser.WhitespaceContext(self, self._ctx, self.state)
- self.enterRule(localctx, 32, self.RULE_whitespace)
+ self.enterRule(localctx, 36, self.RULE_whitespace)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 149
+ self.state = 176
self._errHandler.sync(self)
- _alt = 1
- while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER:
- if _alt == 1:
- self.state = 148
- _la = self._input.LA(1)
- if not(_la==zoiaParser.Newline or _la==zoiaParser.Spaces):
- self._errHandler.recoverInline(self)
- else:
- self._errHandler.reportMatch(self)
- self.consume()
-
+ _la = self._input.LA(1)
+ while True:
+ self.state = 175
+ _la = self._input.LA(1)
+ if not(_la==zoiaParser.Newline or _la==zoiaParser.Spaces):
+ self._errHandler.recoverInline(self)
else:
- raise NoViableAltException(self)
- self.state = 151
+ self._errHandler.reportMatch(self)
+ self.consume()
+ self.state = 178
self._errHandler.sync(self)
- _alt = self._interp.adaptivePredict(self._input,19,self._ctx)
+ _la = self._input.LA(1)
+ if not (_la==zoiaParser.Newline or _la==zoiaParser.Spaces):
+ break
except RecognitionException as re:
localctx.exception = re
diff --git a/src/grammar/zoiaVisitor.py b/src/grammar/zoiaVisitor.py
index b5902ff..1eb629c 100644
--- a/src/grammar/zoiaVisitor.py
+++ b/src/grammar/zoiaVisitor.py
@@ -34,6 +34,11 @@ def visitLineElementsInner(self, ctx:zoiaParser.LineElementsInnerContext):
return self.visitChildren(ctx)
+ # Visit a parse tree produced by zoiaParser#lineElementsArg.
+ def visitLineElementsArg(self, ctx:zoiaParser.LineElementsArgContext):
+ return self.visitChildren(ctx)
+
+
# Visit a parse tree produced by zoiaParser#em3LineElement.
def visitEm3LineElement(self, ctx:zoiaParser.Em3LineElementContext):
return self.visitChildren(ctx)
@@ -59,6 +64,11 @@ def visitTextFragmentReq(self, ctx:zoiaParser.TextFragmentReqContext):
return self.visitChildren(ctx)
+ # Visit a parse tree produced by zoiaParser#textFragmentWord.
+ def visitTextFragmentWord(self, ctx:zoiaParser.TextFragmentWordContext):
+ return self.visitChildren(ctx)
+
+
# Visit a parse tree produced by zoiaParser#alias.
def visitAlias(self, ctx:zoiaParser.AliasContext):
return self.visitChildren(ctx)
diff --git a/src/parse_converter.py b/src/parse_converter.py
index 5911322..abfde92 100644
--- a/src/parse_converter.py
+++ b/src/parse_converter.py
@@ -23,12 +23,12 @@
ANTLR parse tree."""
from io import StringIO
-from antlr4.tree.Tree import TerminalNodeImpl
+from antlr4.tree.Tree import TerminalNodeImpl, ParseTree
from ast_nodes import AliasNode, CommandNode, HeaderNode, KwdArgumentNode, \
LineNode, StdArgumentNode, TextFragmentNode, ZoiaFileNode, \
LineElementsNode, AArgumentNode, Em1LineElementNode, Em2LineElementNode, \
- Em3LineElementNode
+ Em3LineElementNode, AASTNode
from exception import ParseConversionError
from grammar import zoiaParser, zoiaVisitor
from src_pos import SourcePos
@@ -46,20 +46,23 @@ class ParseConverter(zoiaVisitor):
"""Converts an ANTLR parse tree into a Zoia AST."""
def __init__(self, parsed_file: str) -> None:
self.parsed_file = parsed_file
- # Avoids a bunch of 'if isinstance' checks in visitLineElements and
- # visitLineElementsInner
+ # Avoids a bunch of 'if isinstance' checks in visitLineElements,
+ # visitLineElementsInner and visitLineElementsArg
shared_lookup = {
zoiaParser.AliasContext: self.visitAlias,
zoiaParser.CommandContext: self.visitCommand,
}
- self._line_element_inner_lookup = shared_lookup | {
- zoiaParser.TextFragmentReqContext: self.visitTextFragmentReq,
- }
self._line_element_lookup = shared_lookup | {
+ zoiaParser.TextFragmentContext: self.visitTextFragment,
zoiaParser.Em1LineElementContext: self.visitEm1LineElement,
zoiaParser.Em2LineElementContext: self.visitEm2LineElement,
zoiaParser.Em3LineElementContext: self.visitEm3LineElement,
- zoiaParser.TextFragmentContext: self.visitTextFragment,
+ }
+ self._line_element_inner_lookup = shared_lookup | {
+ zoiaParser.TextFragmentReqContext: self.visitTextFragmentReq,
+ }
+ self._line_element_arg_lookup = self._line_element_lookup | {
+ zoiaParser.TextFragmentWordContext: self.visitTextFragmentWord,
}
def make_pos(self, ctx) -> SourcePos:
@@ -67,6 +70,11 @@ def make_pos(self, ctx) -> SourcePos:
return SourcePos(src_file=self.parsed_file, src_line=ctx.start.line,
src_char=ctx.start.column)
+ # Override to add typing
+ def visit(self, tree: ParseTree) -> AASTNode:
+ # pylint: disable=useless-super-delegation
+ return super().visit(tree)
+
# Sorted by the order in which they are defined in the grammar
def visitZoiaFile(self, ctx: zoiaParser.ZoiaFileContext) -> ZoiaFileNode:
header = self.visitHeader(ctx.header())
@@ -94,6 +102,11 @@ def visitLineElementsInner(self,
return self._visit_line_elements_shared(
ctx, self._line_element_inner_lookup)
+ def visitLineElementsArg(self, ctx: zoiaParser.LineElementsArgContext) \
+ -> LineElementsNode:
+ return self._visit_line_elements_shared(
+ ctx, self._line_element_arg_lookup)
+
def _visit_line_elements_shared(self, ctx, visit_lookup) \
-> LineElementsNode:
"""Small helper method to deduplicate the shared logic of
@@ -152,6 +165,15 @@ def visitTextFragmentReq(self, ctx: zoiaParser.TextFragmentReqContext) \
f"text fragment '{ctx.getText()}'")
return TextFragmentNode(s.getvalue(), src_pos=self.make_pos(ctx))
+ def visitTextFragmentWord(self, ctx: zoiaParser.TextFragmentWordContext) \
+ -> TextFragmentNode:
+ s = StringIO()
+ s.write(ctx.Word().getText())
+ child_spaces = ctx.Spaces()
+ if child_spaces:
+ s.write(child_spaces.getText())
+ return TextFragmentNode(s.getvalue(), src_pos=self.make_pos(ctx))
+
def visitAlias(self, ctx: zoiaParser.AliasContext) -> AliasNode:
return AliasNode(ctx.Word().getText(),
src_pos=self.make_pos(ctx))
@@ -182,11 +204,12 @@ def visitArgument(self, ctx: zoiaParser.ArgumentContext) -> AArgumentNode:
def visitKwdArgument(self, ctx: zoiaParser.KwdArgumentContext) \
-> KwdArgumentNode:
kwd_name = ctx.Word().getText()
- arg_value = self.visitLineElements(ctx.lineElements())
+ arg_value = self.visitLineElementsArg(ctx.lineElementsArg())
# Reverse order due to dataclass inheritance
return KwdArgumentNode(arg_value, kwd_name, src_pos=self.make_pos(ctx))
def visitStdArgument(self, ctx: zoiaParser.StdArgumentContext) \
-> StdArgumentNode:
- return StdArgumentNode(self.visitLineElements(ctx.lineElements()),
- src_pos=self.make_pos(ctx))
+ return StdArgumentNode(
+ self.visitLineElementsArg(ctx.lineElementsArg()),
+ src_pos=self.make_pos(ctx))
diff --git a/src/project/chapter.py b/src/project/chapter.py
index 0361555..14e9bd2 100644
--- a/src/project/chapter.py
+++ b/src/project/chapter.py
@@ -47,6 +47,13 @@ def __lt__(self, other) -> bool:
return NotImplemented
return self.chapter_index < other.chapter_index
+ def get_zoia_file(self, zoia_name: str) -> ZoiaFile | None:
+ if zoia_name == 'main.zoia':
+ return self.main_file
+ # @dataclass with slots=True breaks argument-less super
+ # pylint: disable=super-with-arguments
+ return super(Chapter, self).get_zoia_file(zoia_name)
+
@classmethod
def parse_chapter(cls, chapter_folder: Path, project_folder: Path, /, *,
raise_errors: bool):
diff --git a/src/project/config.py b/src/project/config.py
index 72dd9ed..5e483c7 100644
--- a/src/project/config.py
+++ b/src/project/config.py
@@ -23,7 +23,7 @@
import inspect
import os
from collections import defaultdict
-from dataclasses import dataclass
+from dataclasses import dataclass, field
from pathlib import Path
from typing import Type, Any
@@ -31,20 +31,16 @@
import log
from exception import AbstractError
-from utils import ps_error
+from utils import ps_error, valid_src_path, valid_zoia_path
# Internal API begins here
+@dataclass(slots=True)
class _AOption:
"""Base class for all options. See its subclasses like _ASrcPathOption for
more information."""
option_name: str
option_value: Any
- option_default: Any
- __slots__ = ('option_name', 'option_value',)
-
- def __init__(self, opt_name: str, opt_value: Any):
- self.option_name = opt_name
- self.option_value = opt_value
+ option_default: Any = field(init=False)
@classmethod
def parse_option(cls, option_value: Any, option_name: str,
@@ -62,12 +58,10 @@ def _do_parse_option(cls, option_value: Any, option_name: str,
project_folder: Path, /, *, raise_errors: bool):
"""The actual abstract method that does the parsing. This is what you
have to override to create a new type of option."""
- raise AbstractError(cls.parse_option)
-
- def __repr__(self):
- return f"Option<{self.option_name} = '{self.option_value}'>"
+ raise AbstractError()
# TODO Do we need src path options separate from Zoia path options?
+@dataclass(slots=True)
class _ASrcPathOption(_AOption):
"""Base class for src path options. A path, specified relative to the 'src'
folder. Must be entirely lowercase and must exist.
@@ -75,7 +69,6 @@ class _ASrcPathOption(_AOption):
Do not use this directly. Instead, use the _src_path_option API and pass a
default value."""
option_value: Path
- __slots__ = ()
@classmethod
def _do_parse_option(cls, option_value: str | None, option_name: str,
@@ -84,10 +77,10 @@ def _do_parse_option(cls, option_value: str | None, option_name: str,
option_value = option_value.replace(
'\\', os.path.sep).replace('/', os.path.sep)
# This is a src-relative path, which must be lowercased
- if option_value.lower() != option_value:
- return ps_error(f"Failed to parse option '{option_name}': "
- f"'{option_value}' is not lowercased",
- Path('zoia.toml'), raise_errors)
+ if not valid_src_path(option_value):
+ ps_error(f"Failed to parse option '{option_name}': "
+ f"'{option_value}' is not lowercased",
+ Path('zoia.toml'), raise_errors)
# Check if the path actually exists
rel_path = Path('src') / option_value
final_path = project_folder / rel_path
@@ -110,6 +103,7 @@ def _do_parse_option(cls, option_value: str | None, option_name: str,
# __slots__ = ()
# return _SrcPathOption
+@dataclass(slots=True)
class _AZoiaPathOption(_ASrcPathOption):
"""Base class for Zoia path options. Similar to _ASrcPathOption, but must
end in .zoia.
@@ -119,12 +113,13 @@ class _AZoiaPathOption(_ASrcPathOption):
@classmethod
def _do_parse_option(cls, option_value: str | None, option_name: str,
project_folder: Path, /, *, raise_errors: bool):
- # lower() because the check for lowercasing is done in _ASrcPathOption
- if not option_value.lower().endswith('.zoia'):
+ # Error from !valid_src_path(option_value) will be raised in super
+ if valid_src_path(option_value) and not valid_zoia_path(option_value):
return ps_error(f"Failed to parse option '{option_name}': "
f"Specified path '{option_value}' does not end in "
f"'.zoia'", Path('zoia.toml'), raise_errors)
- return super()._do_parse_option(
+ # @dataclass with slots=True breaks argument-less super
+ return super(_AZoiaPathOption, cls)._do_parse_option(
option_value, option_name, project_folder,
raise_errors=raise_errors)
diff --git a/src/project/dir_base.py b/src/project/dir_base.py
index 59c128b..6ebd1dd 100644
--- a/src/project/dir_base.py
+++ b/src/project/dir_base.py
@@ -20,6 +20,7 @@
#
# =============================================================================
"""Implements shared code for all types of project folders."""
+from collections import defaultdict
from dataclasses import dataclass, field
from pathlib import Path
@@ -30,6 +31,16 @@
class _ADirBase:
"""Base class for all project folders."""
zoia_files: list[ZoiaFile] = field(kw_only=True)
+ _id_zoia: defaultdict[str, ZoiaFile | None] = field(init=False)
+
+ def __post_init__(self):
+ self._id_zoia = defaultdict(lambda: None, {
+ z.file_path.name: z for z in self.zoia_files})
+
+ def get_zoia_file(self, zoia_name: str) -> ZoiaFile | None:
+ """Returns the ZoiaFile matching the specified name or None if such a
+ ZoiaFile does not exist in this folder."""
+ return self._id_zoia[zoia_name]
@staticmethod
def parse_zoia_files(curr_folder: Path, project_folder: Path, /, *,
diff --git a/src/project/project.py b/src/project/project.py
index 9b34c59..4f040de 100644
--- a/src/project/project.py
+++ b/src/project/project.py
@@ -27,28 +27,114 @@
import log
from project.config import ZoiaToml
from project.series import Series
-from utils import ps_error
+from project.zoia_file import ZoiaFile
+from utils import ps_error, valid_zoia_path
@dataclass(slots=True)
class Project:
"""The Project class oversees all operations on a project written in
Zoia. To obtain a Project instance, use the parse_project classmethod."""
+ project_path: Path
series: Series
config: ZoiaToml
+ def find_zoia_file(self, file_path: Path) -> ZoiaFile | None:
+ """Finds a ZoiaFile by its path. The path may be relative to the src
+ folder, relative to the project folder, or absolute. Returns None if
+ the file could not be found."""
+ # First make sure the path exists and make it absolute
+ try:
+ if not file_path.is_absolute():
+ # Not absolute, so relative to either the src or project folder
+ altered_path = self.project_path / 'src' / file_path
+ if not altered_path.exists():
+ altered_path = self.project_path / file_path
+ else:
+ # Already absolute, just check that it exists
+ altered_path = file_path
+ file_path = altered_path.resolve(strict=True)
+ except FileNotFoundError:
+ return None
+ # Then relativize it and make sure it's a valid Zoia path
+ rel_path = self.relativize(file_path, strip_src=True)
+ if not valid_zoia_path(str(rel_path)):
+ return None
+ # Then we can parse it by parts and look for the file
+ #path_parts =
+ match rel_path.parts:
+ case (zoia_name,): # a.zoia
+ return self.series.get_zoia_file(zoia_name)
+ case (work_name, zoia_name): # work1/a.zoia
+ work = self.series.get_work(work_name)
+ # PEP 505 or something similar sorely missed
+ if work is None:
+ return None
+ return work.get_zoia_file(zoia_name)
+ case (work_name, chapter_name, zoia_name): # work1/ch1/a.zoia
+ work = self.series.get_work(work_name)
+ if work is None:
+ return None
+ chapter = work.get_chapter(chapter_name)
+ if chapter is None:
+ return None
+ return chapter.get_zoia_file(zoia_name)
+ case _: # Some kind of unsupported location
+ return None
+
+ def _find_zoia_or_raise(self, file_path: Path) -> ZoiaFile:
+ """Internal version of find_zoia_file that raises an error if the file
+ could not be found. Meant to be used for required Zoia files, e.g.
+ aliases.zoia and dictionary.zoia."""
+ ret_zoia = self.find_zoia_file(file_path)
+ if ret_zoia is None:
+ raise FileNotFoundError(f"Failed to find required Zoia file "
+ f"'{file_path}'")
+ return ret_zoia
+
+ def relativize(self, absolute_path: Path, /, *,
+ strip_src: bool = False) -> Path:
+ """Returns a version of the specified absolute path relative to the
+ path at which this project is located. If the specified path is not
+ absolute or not relative to this project, a ValueError is raised.
+
+ :param absolute_path: The path to relativize.
+ :param strip_src: If True, remove the leading 'src' from the resulting
+ relative path. In other words, relativize to the src path instead
+ of the project path."""
+ if not absolute_path.is_absolute():
+ raise ValueError('relativize needs an absolute path')
+ rel_target = self.project_path
+ if strip_src:
+ rel_target /= 'src'
+ return absolute_path.relative_to(rel_target)
+
+ @property
+ def aliases_file(self) -> ZoiaFile:
+ """Returns the ZoiaFile object corresponding to the aliases file. This
+ takes any changes made by the config file into account."""
+ return self._find_zoia_or_raise(
+ self.config.aliases.src_path.option_value)
+
+ @property
+ def dictionary_file(self) -> ZoiaFile:
+ """Returns the ZoiaFile object corresponding to the dictionary file.
+ This takes any changes made by the config file into account."""
+ return self._find_zoia_or_raise(
+ self.config.dictionary.src_path.option_value)
+
@classmethod
def parse_project(cls, project_folder: Path, /, *,
raise_errors: bool = False):
"""Parses a project at the specified path."""
- log.info(f'Wanted project folder is $fWl${project_folder}$R$')
# Resolve the path first so all later operations can use full paths and
# ensure it exists while we're at it
try:
project_folder = project_folder.resolve(strict=True)
except FileNotFoundError as e:
- return ps_error('No project folder found', Path(''),
- raise_errors, orig_error=e)
- log.info(f'Actual project folder is $fWl${project_folder}$R$')
+ return ps_error('Project folder not found',
+ project_folder.resolve(), raise_errors,
+ orig_error=e)
+ log.info(f'Project folder is $fWl${project_folder}$R$')
# Parse the series folder 'src', which must exist
series_rel = 'src'
series_folder = project_folder / series_rel
@@ -72,4 +158,4 @@ def parse_project(cls, project_folder: Path, /, *,
log.warning(f'Failed to parse project due to errors when parsing '
f'$fCl${zoia_toml_rel}$R$')
return None
- return cls(parsed_series, parsed_config)
+ return cls(project_folder, parsed_series, parsed_config)
diff --git a/src/project/series.py b/src/project/series.py
index 62bda07..c07d159 100644
--- a/src/project/series.py
+++ b/src/project/series.py
@@ -20,7 +20,8 @@
#
# =============================================================================
"""Implements series folders."""
-from dataclasses import dataclass
+from collections import defaultdict
+from dataclasses import dataclass, field
from pathlib import Path
import log
@@ -33,6 +34,22 @@ class Series(_ADirBase):
"""A series is the main 'src' folder, containing one or more works in
it."""
works: list[Work]
+ _id_works: defaultdict[int, Work | None] = field(init=False)
+
+ def __post_init__(self):
+ # @dataclass with slots=True breaks argument-less super
+ # pylint: disable=super-with-arguments
+ super(Series, self).__post_init__()
+ self._id_works = defaultdict(lambda: None, {
+ w.work_index: w for w in self.works})
+
+ def get_work(self, work_name: str) -> Work | None:
+ """Returns the work matching the specified name or None if such a work
+ does not exist in this series."""
+ work_ma = match_work(work_name)
+ if not work_ma:
+ return None # Invalid work name syntax
+ return self._id_works[int(work_ma.group(1))]
@classmethod
def parse_series(cls, series_folder: Path, project_folder: Path, /, *,
diff --git a/src/project/work.py b/src/project/work.py
index fd8f5c3..1a7ee28 100644
--- a/src/project/work.py
+++ b/src/project/work.py
@@ -21,7 +21,8 @@
# =============================================================================
"""Implements work folders."""
import re
-from dataclasses import dataclass
+from collections import defaultdict
+from dataclasses import dataclass, field
from functools import total_ordering
from pathlib import Path
@@ -40,12 +41,28 @@ class Work(_ADirBase):
"""A work folder is a folder containing one or more chapters."""
chapters: list[Chapter]
work_index: int
+ _id_chapters: defaultdict[int, Chapter | None] = field(init=False)
+
+ def __post_init__(self):
+ # @dataclass with slots=True breaks argument-less super
+ # pylint: disable=super-with-arguments
+ super(Work, self).__post_init__()
+ self._id_chapters = defaultdict(lambda: None, {
+ c.chapter_index: c for c in self.chapters})
def __lt__(self, other) -> bool:
if not isinstance(other, Work):
return NotImplemented
return self.work_index < other.work_index
+ def get_chapter(self, chapter_name) -> Chapter | None:
+ """Returns the chapter matching the specified name or None if such a
+ chapter does not exist in this work."""
+ chapter_ma = match_chapter(chapter_name)
+ if not chapter_ma:
+ return None # Invalid chapter name syntax
+ return self._id_chapters[int(chapter_ma.group(1))]
+
@classmethod
def parse_work(cls, work_folder: Path, project_folder: Path, /, *,
raise_errors: bool):
diff --git a/src/project/zoia_file.py b/src/project/zoia_file.py
index 0cc3d7d..66610f1 100644
--- a/src/project/zoia_file.py
+++ b/src/project/zoia_file.py
@@ -20,28 +20,22 @@
#
# =============================================================================
"""Implements .zoia files."""
-from dataclasses import dataclass
-from enum import Enum
+from dataclasses import dataclass, field
from functools import total_ordering
from pathlib import Path
import log
from ast_nodes import ZoiaFileNode
-from exception import ParseConversionError, ParsingError
+from exception import ParseConversionError, ParsingError, ValidationError
from zoia_processor import process_zoia_file
-# FIXME finish
-class FileType(Enum):
- """Represents the various header types that Zoia files can have."""
- ALIASES = 0
-
@dataclass(slots=True)
@total_ordering
class ZoiaFile:
"""A Zoia file is a file with the .zoia extension, following the layout
specified by the Zoia grammar."""
file_path: Path
- file_ast: ZoiaFileNode
+ file_ast: ZoiaFileNode = field(repr=False)
def is_main_file(self) -> bool:
"""Checks if this is a main.zoia file."""
@@ -77,4 +71,12 @@ def parse_zoia_file(cls, file_path: Path, project_folder: Path, /, *,
f'$fWl${p.src_line}$fT$, column $fWl${p.src_char}$fT$: '
f'$fRl${e.orig_msg}$fT$')
return None
+ except ValidationError as e:
+ if raise_errors:
+ raise
+ p = e.src_pos
+ log.error(f'Failed to validate $fWl${p.src_file}$fT$ at line '
+ f'$fWl${p.src_line}$fT$, column $fWl${p.src_char}$fT$: '
+ f'$fRl${e.orig_msg}$fT$')
+ return None
return cls(file_path, processed_file)
diff --git a/src/test/base.py b/src/test/base.py
index dc56255..2d2b3e2 100644
--- a/src/test/base.py
+++ b/src/test/base.py
@@ -31,6 +31,11 @@
_DEFAULT_HEADER = '\\header[fragment]\n\n'
+def mks(*lines):
+ """Makes a Zoia string using the specified lines (with a header
+ prepended)."""
+ return _DEFAULT_HEADER + '\n'.join(lines) + '\n'
+
class ATestParser:
"""Base class for all tests that need to parse Zoia code."""
_test_src: str
diff --git a/src/test/test_mapper.py b/src/test/test_ast_mapper.py
similarity index 82%
rename from src/test/test_mapper.py
rename to src/test/test_ast_mapper.py
index 21612a0..4e8f2a9 100644
--- a/src/test/test_mapper.py
+++ b/src/test/test_ast_mapper.py
@@ -20,17 +20,19 @@
#
# =============================================================================
"""This module houses tests related to ast_mapper."""
-from test.test_canonical import mkr, ATestCanonicalRepr, TestHeaderCR, \
+from test.base import mks
+from test.test_canonical import ATestCanonicalRepr, TestHeaderCR, \
TestCommentCR, TestTextFragmentCR, TestAliasCR, TestAliasBarCR, \
TestCommandNoArgCR, TestCommandWithArgCR, TestKeywordArgsCR, \
- TestCommandWhitespaceCR, TestCommandMarkupCR, TestCommandNestedCR, \
+ TestCommandWhitespaceCR, TestCommandMarkupCR, TestCommandNestedSACR, \
TestUnicodeCR, TestEm1CR, TestEm2CR, TestEm3CR, TestEm1ComplexCR, \
- TestEm2ComplexCR, TestEm3ComplexCR, TestMarkupCombinedCR
+ TestEm2ComplexCR, TestEm3ComplexCR, TestMarkupCombinedCR, \
+ TestCommandNestedMACR
from ast_mapper import AASTMapper
from ast_nodes import AliasNode, TextFragmentNode
-class _MapperTest(AASTMapper):
+class _TestMapper(AASTMapper):
"""Test mapper implementation that simply replaces AliasNodes with
TextFragmentNodes (without changing the text)."""
def visit_alias(self, node: AliasNode):
@@ -42,7 +44,7 @@ class _ATestASTMapper(ATestCanonicalRepr):
"""Base class for AASTMapper tests."""
def _get_canonical(self, test_src: str) -> str:
tree = self._parse_src(test_src)
- mapper = _MapperTest()
+ mapper = _TestMapper()
tree_tf = mapper.visit(tree)
return tree_tf.canonical()
@@ -71,8 +73,11 @@ class TestMapCommandWhitespaceCR(_ATestASTMapper, TestCommandWhitespaceCR):
class TestMapCommandMarkupCR(_ATestASTMapper, TestCommandMarkupCR):
"""Version of TestCommandMarkupCR that maps before testing."""
-class TestMapCommandNestedCR(_ATestASTMapper, TestCommandNestedCR):
- """Version of TestCommandNestedCR that maps before testing."""
+class TestMapCommandNestedSACR(_ATestASTMapper, TestCommandNestedSACR):
+ """Version of TestCommandNestedSACR that maps before testing."""
+
+class TestMapCommandNestedMACR(_ATestASTMapper, TestCommandNestedMACR):
+ """Version of TestCommandNestedMACR that maps before testing."""
class TestMapUnicodeCR(_ATestASTMapper, TestUnicodeCR):
"""Version of TestUnicodeCR that maps before testing."""
@@ -92,27 +97,28 @@ class TestMapMarkupCombinedCR(_ATestASTMapper, TestMarkupCombinedCR):
# Canonical repr tests with aliases in it should remove the '@' and '|'
class TestMapAliasCR(_ATestASTMapper, TestAliasCR):
"""@foo| -> 'foo', @bar| -> 'bar', @qux| -> 'qux'"""
- _test_rep = mkr('foobar qux')
+ _test_rep = mks('foobar qux')
class TestMapAliasBarCR(_ATestASTMapper, TestAliasBarCR):
"""@A -> 'A', @B| -> 'B', @C, -> 'C,', @D| -> D"""
- _test_rep = mkr('A ran into B, C, and D.')
+ _test_rep = mks('A ran into B, C, and D.')
class TestMapEm1ComplexCR(_ATestASTMapper, TestEm1ComplexCR):
"""@aliases -> aliases"""
- _test_rep = mkr('*Em1 with aliases and \\commands|*')
+ _test_rep = mks('*Em1 with aliases and \\commands|*')
class TestMapEm2ComplexCR(_ATestASTMapper, TestEm2ComplexCR):
"""@aliases -> aliases"""
- _test_rep = mkr('**Em2 with aliases and \\commands|**')
+ _test_rep = mks('**Em2 with aliases and \\commands|**')
class TestMapEm3ComplexCR(_ATestASTMapper, TestEm3ComplexCR):
"""@aliases -> aliases"""
- _test_rep = mkr('***Em3 with aliases and \\commands|***')
+ _test_rep = mks('***Em3 with aliases and \\commands|***')
# Delete these, otherwise pytest will see them in scope and run them again
del ATestCanonicalRepr, TestHeaderCR, TestCommentCR, TestTextFragmentCR, \
TestAliasCR, TestAliasBarCR, TestCommandNoArgCR, TestCommandWithArgCR, \
TestKeywordArgsCR, TestCommandWhitespaceCR, TestCommandMarkupCR, \
- TestCommandNestedCR, TestUnicodeCR, TestEm1CR, TestEm2CR, TestEm3CR, \
- TestEm1ComplexCR, TestEm2ComplexCR, TestEm3ComplexCR, TestMarkupCombinedCR
+ TestCommandNestedSACR, TestUnicodeCR, TestEm1CR, TestEm2CR, TestEm3CR, \
+ TestEm1ComplexCR, TestEm2ComplexCR, TestEm3ComplexCR, \
+ TestMarkupCombinedCR, TestCommandNestedMACR
diff --git a/src/test/test_ast_validator.py b/src/test/test_ast_validator.py
new file mode 100644
index 0000000..866acbc
--- /dev/null
+++ b/src/test/test_ast_validator.py
@@ -0,0 +1,85 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""This module houses tests related to ast_validator."""
+from test.base import ATestParser
+
+import pytest
+
+from exception import ValidationError
+
+class _ATestValidatorPass(ATestParser):
+ """Base class for passing validator tests."""
+ def test_validator_passes(self):
+ """Asserts that parsing and validating the source works."""
+ assert self._parse_src()
+
+class _ATestValidatorFail(ATestParser):
+ """Base class for failing validator tests."""
+ _exp_error: str
+
+ def test_validator_fails(self):
+ """Asserts that parsing the source works, but validation fails."""
+ try:
+ self._parse_src()
+ pytest.fail('Validation was supposed to fail, but succeeded '
+ 'instead')
+ except ValidationError as e:
+ assert self._exp_error in str(e)
+
+# Passing tests begin here
+class TestHeaderSimple(_ATestValidatorPass):
+ """A header with a single-word text fragment as the type should be
+ accepted."""
+ _test_src = '\\header[fragment]'
+
+# TODO See ast_validator re: if we even want this behavior
+class TestHeaderMultiArgStd(_ATestValidatorPass):
+ """A header with a valid type and a second standard argument should be
+ accepted."""
+ _test_src = '\\header[fragment; second arg]'
+
+class TestHeaderMultiArgKwd(_ATestValidatorPass):
+ """A header with a valid type and a second keyword argument should be
+ accepted."""
+ _test_src = '\\header[fragment; arg2 = two]'
+
+# Failing tests begin here
+class TestHeaderKwdArg(_ATestValidatorFail):
+ """A header with a keyword argument as its first argument should be
+ rejected."""
+ _test_src = '\\header[type = fragment]'
+ _exp_error = ('The first argument passed to \\header must be a standard '
+ 'argument')
+
+class TestHeaderMultiStdArg(_ATestValidatorFail):
+ """A header with a multi-word text fragment as its first argument should be
+ rejected."""
+ _test_src = '\\header[fragment one]'
+ _exp_error = ('The first argument passed to \\header must be a single '
+ 'text fragment containing one word')
+
+class TestHeaderNoTextFragment(_ATestValidatorFail):
+ """A header with something other than a text fragment as its first argument
+ should be rejected."""
+ _test_src = '\\header[@some_alias]'
+ _exp_error = ('The first argument passed to \\header must be a single '
+ 'text fragment containing one word')
diff --git a/src/test/test_visitor.py b/src/test/test_ast_visitor.py
similarity index 100%
rename from src/test/test_visitor.py
rename to src/test/test_ast_visitor.py
diff --git a/src/test/test_canonical.py b/src/test/test_canonical.py
index d951e92..47f284a 100644
--- a/src/test/test_canonical.py
+++ b/src/test/test_canonical.py
@@ -20,7 +20,7 @@
#
# =============================================================================
"""This module houses tests related to canonical representations."""
-from test.base import ATestParser
+from test.base import ATestParser, mks
class ATestCanonicalRepr(ATestParser):
"""Base class for tests that check canonical representations."""
@@ -39,42 +39,20 @@ def test_parse_repr(self) -> None:
representation itself again."""
assert self._get_canonical(self._test_rep) == self._test_rep
-
-# Some helpers for easily making sources and canonical representations
-def _mk_shared(*lines) -> str:
- """Adds newlines to the specified lines and adds a trailing one to the
- end."""
- return '\n'.join(lines) + '\n'
-
-_COMMON_S = _mk_shared('\\header[foo]') + '\n'
-_COMMON_R = _mk_shared('\\header[',
- ' foo;',
- ']',
- '')
-
-def mks(*lines):
- """Makes a source 'file' using the specified lines (with a header
- prepended)."""
- return _COMMON_S + _mk_shared(*lines)
-def mkr(*lines):
- """Makes a canonical representation 'file' using the specified lines (with
- a header prepended)."""
- return _COMMON_R + _mk_shared(*lines)
-
class TestHeaderCR(ATestCanonicalRepr):
"""Headers should be formatted like commands (see TestCommandWithArgCR)."""
_test_src = mks()
- _test_rep = mkr()
+ _test_rep = mks()
class TestCommentCR(ATestCanonicalRepr):
"""Comments should be gone (since they get stripped during parsing)."""
_test_src = mks('This is a line# with a comment')
- _test_rep = mkr('This is a line')
+ _test_rep = mks('This is a line')
class TestTextFragmentCR(ATestCanonicalRepr):
"""Text fragments should be reproduced verbatim, including all spaces."""
_test_src = mks('This is a text fragment')
- _test_rep = mkr('This is a text fragment')
+ _test_rep = mks('This is a text fragment')
class TestAliasCR(ATestCanonicalRepr):
"""Aliases should be reproduced verbatim, barring the added vertical bar
@@ -83,7 +61,7 @@ class TestAliasCR(ATestCanonicalRepr):
some alias usages). The two spaces below become text fragments and are
hence reproduced verbatim as well."""
_test_src = mks('@foo@bar @qux')
- _test_rep = mkr('@foo|@bar| @qux|')
+ _test_rep = mks('@foo|@bar| @qux|')
class TestAliasBarCR(ATestCanonicalRepr):
"""The optional vertical bar terminator for aliases should be handled
@@ -91,19 +69,19 @@ class TestAliasBarCR(ATestCanonicalRepr):
alias (since a comma is perfectly valid as part of a word and hence
perfectly valid as part of an alias name too)."""
_test_src = mks('@A ran into @B|, @C, and @D|.')
- _test_rep = mkr('@A| ran into @B|, @C,| and @D|.')
+ _test_rep = mks('@A| ran into @B|, @C,| and @D|.')
class TestCommandNoArgCR(ATestCanonicalRepr):
"""Commands without arguments should receive the vertical bar as a
terminator."""
_test_src = mks('\\cmd')
- _test_rep = mkr('\\cmd|')
+ _test_rep = mks('\\cmd|')
class TestCommandWithArgCR(ATestCanonicalRepr):
"""Commands with arguments should become multiline and have trailing
semicolons added if missing."""
_test_src = mks('\\cmd[a; b; c]')
- _test_rep = mkr('\\cmd[',
+ _test_rep = mks('\\cmd[',
' a;',
' b;',
' c;',
@@ -113,7 +91,7 @@ class TestKeywordArgsCR(ATestCanonicalRepr):
"""Keyword arguments should be displayed with exactly one space before and
after the equals sign."""
_test_src = mks('\\cmd[a=b;c = d;e =f]')
- _test_rep = mkr('\\cmd[',
+ _test_rep = mks('\\cmd[',
' a = b;',
' c = d;',
' e = f;',
@@ -124,7 +102,7 @@ class TestCommandWhitespaceCR(ATestCanonicalRepr):
correctly in earlier version of the parser."""
_test_src = mks('\\qux[foo ;',
' bar = rab ; ]')
- _test_rep = mkr('\\qux[',
+ _test_rep = mks('\\qux[',
' foo ;',
' bar = rab ;',
']')
@@ -136,65 +114,74 @@ class TestCommandMarkupCR(ATestCanonicalRepr):
' bar = **em2**;',
' qux = Text that is ***em3***.;',
']')
- _test_rep = mkr('\\foo[',
+ _test_rep = mks('\\foo[',
' *em1*;',
' bar = **em2**;',
' qux = Text that is ***em3***.;',
']')
-class TestCommandNestedCR(ATestCanonicalRepr):
- """Nested commands should be handled correctly."""
+class TestCommandNestedSACR(ATestCanonicalRepr):
+ """Single-argument nested commands should be handled correctly."""
_test_src = mks('\\foo[',
' \\bar[',
' \\qux;',
' ];'
']')
- # TODO This is ugly, should somehow come up with a way to fix it
- _test_rep = mkr('\\foo[',
+ _test_rep = mks('\\foo[\\bar[\\qux|]]')
+
+class TestCommandNestedMACR(ATestCanonicalRepr):
+ """Single-argument nested commands should be handled correctly."""
+ _test_src = mks('\\foo[',
+ ' \\bar[',
+ ' \\qux; \\qux',
+ ' ]; \\qux;'
+ ']')
+ # TODO This is ugly, see #18
+ _test_rep = mks('\\foo[',
' \\bar[',
' \\qux|;',
+ ' \\qux|;',
'];',
+ ' \\qux|;',
']')
class TestUnicodeCR(ATestCanonicalRepr):
"""Canonical representations should handle unicode characters correctly."""
_test_src = mks('Внимание \\cömmänd[😀] 警告')
- _test_rep = mkr('Внимание \\cömmänd[',
- ' 😀;',
- '] 警告')
+ _test_rep = mks('Внимание \\cömmänd[😀] 警告')
class TestEm1CR(ATestCanonicalRepr):
"""Em1 text should have an unchanged canonical representation."""
_test_src = mks('This is *em1 text*.')
- _test_rep = mkr('This is *em1 text*.')
+ _test_rep = mks('This is *em1 text*.')
class TestEm2CR(ATestCanonicalRepr):
"""Em2 text should have an unchanged canonical representation."""
_test_src = mks('This is **em2 text**.')
- _test_rep = mkr('This is **em2 text**.')
+ _test_rep = mks('This is **em2 text**.')
class TestEm3CR(ATestCanonicalRepr):
"""Em3 text should have an unchanged canonical representation."""
_test_src = mks('This is ***em3 text***.')
- _test_rep = mkr('This is ***em3 text***.')
+ _test_rep = mks('This is ***em3 text***.')
class TestEm1ComplexCR(ATestCanonicalRepr):
"""Aliases and commands in em1 text should be handled correctly."""
_test_src = mks('*Em1 with @aliases and \\commands*')
- _test_rep = mkr('*Em1 with @aliases| and \\commands|*')
+ _test_rep = mks('*Em1 with @aliases| and \\commands|*')
class TestEm2ComplexCR(ATestCanonicalRepr):
"""Aliases and commands in em2 text should be handled correctly."""
_test_src = mks('**Em2 with @aliases and \\commands**')
- _test_rep = mkr('**Em2 with @aliases| and \\commands|**')
+ _test_rep = mks('**Em2 with @aliases| and \\commands|**')
class TestEm3ComplexCR(ATestCanonicalRepr):
"""Aliases and commands in em3 text should be handled correctly."""
_test_src = mks('***Em3 with @aliases and \\commands***')
- _test_rep = mkr('***Em3 with @aliases| and \\commands|***')
+ _test_rep = mks('***Em3 with @aliases| and \\commands|***')
class TestMarkupCombinedCR(ATestCanonicalRepr):
"""As horrible as this looks, any level of markup should be able to follow
any other level of markup without issues."""
_test_src = mks('*a***b*****c****d***e**')
- _test_rep = mkr('*a***b*****c****d***e**')
+ _test_rep = mks('*a***b*****c****d***e**')
diff --git a/src/test/test_config/missing_sesaila/src/dictionary.zoia b/src/test/test_config/missing_sesaila/src/dictionary.zoia
index 6986344..5f061cc 100644
--- a/src/test/test_config/missing_sesaila/src/dictionary.zoia
+++ b/src/test/test_config/missing_sesaila/src/dictionary.zoia
@@ -1 +1 @@
-\header[dict]
+\header[dictionary]
diff --git a/src/test/test_config/missing_yranoitcid/src/dictionary.zoia b/src/test/test_config/missing_yranoitcid/src/dictionary.zoia
index 6986344..5f061cc 100644
--- a/src/test/test_config/missing_yranoitcid/src/dictionary.zoia
+++ b/src/test/test_config/missing_yranoitcid/src/dictionary.zoia
@@ -1 +1 @@
-\header[dict]
+\header[dictionary]
diff --git a/src/test/test_config/no_config_p/src/dictionary.zoia b/src/test/test_config/no_config_p/src/dictionary.zoia
index 6986344..5f061cc 100644
--- a/src/test/test_config/no_config_p/src/dictionary.zoia
+++ b/src/test/test_config/no_config_p/src/dictionary.zoia
@@ -1 +1 @@
-\header[dict]
+\header[dictionary]
diff --git a/src/test/test_config/present_sesaila_yranoitcid/src/yranoitcid.zoia b/src/test/test_config/present_sesaila_yranoitcid/src/yranoitcid.zoia
index 6986344..5f061cc 100644
--- a/src/test/test_config/present_sesaila_yranoitcid/src/yranoitcid.zoia
+++ b/src/test/test_config/present_sesaila_yranoitcid/src/yranoitcid.zoia
@@ -1 +1 @@
-\header[dict]
+\header[dictionary]
diff --git a/src/test/test_config/unknown_sections_options/src/yranoitcid.zoia b/src/test/test_config/unknown_sections_options/src/yranoitcid.zoia
index 6986344..5f061cc 100644
--- a/src/test/test_config/unknown_sections_options/src/yranoitcid.zoia
+++ b/src/test/test_config/unknown_sections_options/src/yranoitcid.zoia
@@ -1 +1 @@
-\header[dict]
+\header[dictionary]
diff --git a/src/test/test_exception.py b/src/test/test_exception.py
index 1252fb8..03271b7 100644
--- a/src/test/test_exception.py
+++ b/src/test/test_exception.py
@@ -23,8 +23,9 @@
from exception import AbstractError
def test_abstract_msg() -> None:
- """AbstractError should correctly derive qualified method names."""
+ """AbstractError should correctly derive method names and source files."""
try:
- raise AbstractError(test_abstract_msg)
+ raise AbstractError()
except AbstractError as e:
assert 'test_abstract_msg' in str(e)
+ assert 'test_exception' in str(e)
diff --git a/src/test/test_parser.py b/src/test/test_parser.py
index 699875a..a62dbf5 100644
--- a/src/test/test_parser.py
+++ b/src/test/test_parser.py
@@ -84,12 +84,6 @@ class TestAcceptsComment2(_ATestParserPass):
"""A comment at the end of a line should be accepted."""
_test_src = 'foo \\bar @qux # All three types of line element'
-class TestAcceptsSpaceArg(_ATestParserPass):
- """An argument may be nothing but spaces. This is unintuitive at first, but
- comes as a side effect of text fragments potentially being nothing but
- spaces."""
- _test_src = '\\cmd[ ]'
-
class TestAcceptsUnicode(_ATestParserPass):
"""Unicode characters should be accepted."""
_test_src = '\\cömmänd[😀] 警告'
@@ -184,3 +178,7 @@ class TestRejectsKwdEm2(_ATestParserFail):
class TestRejectsKwdEm3(_ATestParserFail):
"""Em3 text should be rejected when used as a keyword."""
_test_src = '\\cmd[***foo*** = bar]'
+
+class TestRejectsSpaceArg(_ATestParserFail):
+ """An argument may not consist entirely of spaces."""
+ _test_src = '\\cmd[ ]'
diff --git a/src/test/test_project/arbitrary_zoia_files/src/dictionary.zoia b/src/test/test_project/arbitrary_zoia_files/src/dictionary.zoia
index 6986344..5f061cc 100644
--- a/src/test/test_project/arbitrary_zoia_files/src/dictionary.zoia
+++ b/src/test/test_project/arbitrary_zoia_files/src/dictionary.zoia
@@ -1 +1 @@
-\header[dict]
+\header[dictionary]
diff --git a/src/test/test_project/base.py b/src/test/test_project/base.py
new file mode 100644
index 0000000..2727dc0
--- /dev/null
+++ b/src/test/test_project/base.py
@@ -0,0 +1,181 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""This module houses code shared by multiple project test files."""
+from pathlib import Path
+from tempfile import mkdtemp
+import os
+import shutil
+
+from test.base import ATestProjectPassing
+
+import pytest
+
+from exception import AbstractError
+from project import Project
+
+class _ACurrentFile(ATestProjectPassing):
+ """Base class for tests in the test_project package."""
+ _py_file_path = __file__
+
+class _ATestArbitraryZoiaFiles(_ACurrentFile):
+ """Base class for tests that want to make use of the arbitrary_zoia_files
+ test project."""
+ _test_name = 'arbitrary_zoia_files'
+
+class _ATestSimpleStructure(_ACurrentFile):
+ """Base class for tests that want to make use of the simple_structure test
+ project."""
+ _test_name = 'simple_structure'
+
+class _ATestSingleFile(_ACurrentFile):
+ """Base class for testing single files like aliases_file and
+ dictionary_file."""
+ _project: Project
+ _file_attr: str
+ _file_name: str
+
+ def _cfg_path(self):
+ """"""
+ raise AbstractError()
+
+ def _assert_file_passes(self):
+ single_file = getattr(self._project, self._file_attr)
+ # Check is only here to shut linters up
+ assert single_file.file_path.suffix == '.zoia'
+
+ def _assert_file_fails(self):
+ try:
+ single_file = getattr(self._project, self._file_attr)
+ single_file.is_main_file() # Call is only here to shut linters up
+ pytest.fail(f'Retrieved {self._file_attr}, but expected to fail')
+ except FileNotFoundError:
+ pass
+
+ def test_proj_passes(self) -> None:
+ """Asserts that correct uses of the file pass."""
+ self._project = self._parse_project()
+ cfg_path = self._cfg_path()
+ # Default - absolute path that exists
+ self._assert_file_passes()
+ # Path relative to the src folder that exists
+ cfg_path.option_value = Path(self._file_name)
+ self._assert_file_passes()
+ # Path relative to the project folder that exists (but doesn't
+ # exist relative to the src folder)
+ cfg_path.option_value = Path('src') / self._file_name
+ self._assert_file_passes()
+ # The first chapter's main.zoia file, which must always exist
+ cfg_path.option_value = Path('work1') / 'ch1' / 'main.zoia'
+ self._assert_file_passes()
+
+ def test_proj_fails(self) -> None:
+ """Asserts that various incorrect uses of the file fail."""
+ self._project = self._parse_project()
+ cfg_path = self._cfg_path()
+ p_path = self._project.project_path
+ temp_dir = Path(mkdtemp())
+ try:
+ # Absolute path that doesn't exist
+ cfg_path.option_value = temp_dir / self._file_name
+ self._assert_file_fails()
+ finally:
+ shutil.rmtree(temp_dir)
+ upper_path = p_path / 'src' / self._file_name.capitalize()
+ upper_path.touch()
+ try:
+ # Invalid Zoia path - not lowercased
+ cfg_path.option_value = upper_path
+ self._assert_file_fails()
+ finally:
+ os.remove(upper_path)
+ txt_path = p_path / 'src' / self._file_name.replace('.zoia', '.txt')
+ txt_path.touch()
+ try:
+ # Invalid Zoia path - does not end in .zoia
+ cfg_path.option_value = txt_path
+ self._assert_file_fails()
+ finally:
+ os.remove(txt_path)
+ too_long_dir = p_path / 'src' / 'work1' / 'ch1' / 'foo'
+ too_long_dir.mkdir()
+ too_long_path = too_long_dir / 'main.zoia'
+ too_long_path.touch()
+ try:
+ # Path is too long - we don't support subfolders in chapters
+ cfg_path.option_value = too_long_path
+ self._assert_file_fails()
+ finally:
+ shutil.rmtree(too_long_dir)
+
+ def test_invalid_path_fails(self):
+ """Asserts that uses with incorrect chapter or work names fail."""
+ self._project = self._parse_project()
+ cfg_path = self._cfg_path()
+ p_path = self._project.project_path
+ invalid_chapter_path = p_path / 'src' / 'work1' / 'cha'
+ invalid_chapter_path.mkdir()
+ invalid_chapter_zoia_path = invalid_chapter_path / 'main.zoia'
+ invalid_chapter_zoia_path.touch()
+ try:
+ # Invalid chapter path - 'ch' not followed by a number
+ cfg_path.option_value = invalid_chapter_zoia_path
+ self._assert_file_fails()
+ finally:
+ shutil.rmtree(invalid_chapter_path)
+ invalid_work_path = p_path / 'src' / 'worka'
+ invalid_work_path.mkdir()
+ invalid_work_zoia_path = invalid_work_path / 'aux.zoia'
+ invalid_work_zoia_path.touch()
+ invalid_chapter_path = invalid_work_path / 'cha'
+ invalid_chapter_path.mkdir()
+ invalid_chapter_zoia_path = invalid_chapter_path / 'main.zoia'
+ invalid_chapter_zoia_path.touch()
+ try:
+ # Invalid work path - 'work' not followed by a number
+ cfg_path.option_value = invalid_work_zoia_path
+ self._assert_file_fails()
+ # Invalid chapter path - 'work' not followed by a number
+ cfg_path.option_value = invalid_chapter_zoia_path
+ self._assert_file_fails()
+ finally:
+ shutil.rmtree(invalid_work_path)
+
+class _ATestAuxFiles(_ATestSingleFile):
+ """Variant of _ATestSingleFile that also tests for aux files in various
+ places."""
+ def test_aux_file(self):
+ """Asserts that aliases_file works correctly for aux files in various
+ places too."""
+ self._project = self._parse_project()
+ cfg_path = self._cfg_path()
+ # An auxiliary .zoia file in the src folder
+ for f in ('aux.zoia', self._file_name):
+ cfg_path.option_value = Path(f)
+ self._assert_file_passes()
+ # An auxiliary .zoia file in a work
+ for w in ('work1', 'work2'):
+ cfg_path.option_value = Path(w) / 'aux.zoia'
+ self._assert_file_passes()
+ # An auxiliary .zoia file in a chapter
+ for c in ('ch1', 'ch2'):
+ cfg_path.option_value = Path('work1') / c / 'aux.zoia'
+ self._assert_file_passes()
diff --git a/src/test/test_project/simple_structure/src/dictionary.zoia b/src/test/test_project/simple_structure/src/dictionary.zoia
index 6986344..5f061cc 100644
--- a/src/test/test_project/simple_structure/src/dictionary.zoia
+++ b/src/test/test_project/simple_structure/src/dictionary.zoia
@@ -1 +1 @@
-\header[dict]
+\header[dictionary]
diff --git a/src/test/test_project/test_aliases_file.py b/src/test/test_project/test_aliases_file.py
new file mode 100644
index 0000000..9e4feff
--- /dev/null
+++ b/src/test/test_project/test_aliases_file.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""This module runs tests that check whether aliases_file is correctly
+implemented."""
+from test.test_project.base import _ATestArbitraryZoiaFiles, \
+ _ATestSimpleStructure, _ATestSingleFile, _ATestAuxFiles
+
+class _ATestAliases(_ATestSingleFile):
+ """Base class for testing aliases_file."""
+ _file_attr = 'aliases_file'
+ _file_name = 'aliases.zoia'
+
+ def _cfg_path(self):
+ return self._project.config.aliases.src_path
+
+class TestArbitraryZoiaFilesAliases(_ATestArbitraryZoiaFiles, _ATestAliases,
+ _ATestAuxFiles):
+ """arbitrary_zoia_file should implement aliases_file correctly."""
+
+class TestSimpleStructureAliases(_ATestSimpleStructure, _ATestAliases):
+ """simple_structure should implement aliases_file correctly."""
diff --git a/src/test/test_project/test_dictionary_file.py b/src/test/test_project/test_dictionary_file.py
new file mode 100644
index 0000000..38295ec
--- /dev/null
+++ b/src/test/test_project/test_dictionary_file.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""This module runs tests that check whether dictionary_file is correctly
+implemented."""
+from test.test_project.base import _ATestArbitraryZoiaFiles, \
+ _ATestSimpleStructure, _ATestSingleFile, _ATestAuxFiles
+
+class _ATestDictionary(_ATestSingleFile):
+ """Base class for testing dictionary_file."""
+ _file_attr = 'dictionary_file'
+ _file_name = 'dictionary.zoia'
+
+ def _cfg_path(self):
+ return self._project.config.dictionary.src_path
+
+class TestArbitraryZoiaFilesDictionary(_ATestArbitraryZoiaFiles,
+ _ATestDictionary, _ATestAuxFiles):
+ """arbitrary_zoia_file should implement dictionary_file correctly."""
+
+class TestSimpleStructureDictionary(_ATestSimpleStructure, _ATestDictionary):
+ """simple_structure should implement dictionary_file correctly."""
diff --git a/src/test/test_project/test_project_structure.py b/src/test/test_project/test_project_structure.py
index a8b47a1..56f94e7 100644
--- a/src/test/test_project/test_project_structure.py
+++ b/src/test/test_project/test_project_structure.py
@@ -21,16 +21,15 @@
# =============================================================================
"""This module runs tests that check whether project structures are being
parsed correctly."""
-from test.base import ATestProjectFailing, ATestProjectPassing
+from test.base import ATestProjectFailing
+from test.test_project.base import _ATestArbitraryZoiaFiles, \
+ _ATestSimpleStructure
import pytest
class _ATestPSFailing(ATestProjectFailing):
- """Base class for failing project structure tests."""
- _py_file_path = __file__
-
-class _ATestPSPassing(ATestProjectPassing):
- """Base class for passing project structure tests."""
+ """Base class for failing project structure tests. Needed since these don't
+ derive from _ACurrentFile (yet)."""
_py_file_path = __file__
# Failing tests begin here
@@ -75,7 +74,7 @@ class TestNoProject(_ATestPSFailing):
"""A project without a project folder (i.e. one where the target path
points to a non-existent folder) should be rejected."""
_test_name = 'no_project'
- _exp_error = "No project folder found"
+ _exp_error = "Project folder not found"
class TestNoSrc(_ATestPSFailing):
"""A project without a src folder (i.e. without a series) should be
@@ -106,12 +105,8 @@ class TestUpperWork(_ATestPSFailing):
_exp_error = "'Work1' is not lowercased"
# Passing tests begin here
-class TestArbitraryZoiaFiles(_ATestPSPassing):
- """Zoia files should be accepted and parsed no matter which folder under
- src they are placed in."""
- _test_name = 'arbitrary_zoia_files'
-
-class TestSimpleStructure(_ATestPSPassing):
- """A single work with a single chapter and a valid main.zoia file should be
- accepted."""
- _test_name = 'simple_structure'
+class TestArbitraryZoiaFilesParses(_ATestArbitraryZoiaFiles):
+ """arbitrary_zoia_file should parse."""
+
+class TestSimpleStructureParses(_ATestSimpleStructure):
+ """simple_structure should parse."""
diff --git a/src/test/test_project/test_relativize.py b/src/test/test_project/test_relativize.py
new file mode 100644
index 0000000..19968a6
--- /dev/null
+++ b/src/test/test_project/test_relativize.py
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+#
+# GPL License and Copyright Notice ============================================
+#
+# This file is part of Zoia, a language for writing fiction.
+# Copyright (C) 2021-2022 Infernio
+#
+# 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 .
+#
+# =============================================================================
+"""This module runs tests that check whether relativize is correctly
+implemented."""
+from pathlib import Path
+from tempfile import gettempdir
+
+from test.base import ATestProjectPassing
+from test.test_project.base import _ATestArbitraryZoiaFiles, \
+ _ATestSimpleStructure
+
+import pytest
+
+class _ATestRelativize(ATestProjectPassing):
+ """Base class for passing project structure tests that also want to test
+ their relativize implementation."""
+ def test_proj_passes(self) -> None:
+ """Asserts that relativize is correctly implemented."""
+ project = self._parse_project()
+ p_rel = project.relativize
+ # Simple passing tests
+ p_path = project.project_path
+ assert p_rel(p_path) == Path('')
+ assert p_rel(p_path / 'src') == Path('src')
+ assert p_rel(p_path / 'src', strip_src=True) == Path('')
+ assert p_rel(p_path / 'foo' / 'bar') == Path('foo') / 'bar'
+ assert p_rel(p_path / 'src' / 'foo' / 'bar',
+ strip_src=True) == Path('foo') / 'bar'
+ # Paths that cannot be relativized are rejected by raising an error
+ tmp_path = Path(gettempdir()) / 'foo'
+ try:
+ p_rel(tmp_path)
+ pytest.fail(f'relativize should fail with paths that cannot be '
+ f'relativized, but succeeded for {tmp_path}')
+ except ValueError:
+ pass # Not under our control, don't check the message
+ # Already relative paths are rejected by raising an error
+ rel_path = Path('foo') / 'bar' / 'qux'
+ try:
+ p_rel(rel_path)
+ pytest.fail(f'relativize should fail with relative paths, but '
+ f'succeeded for {rel_path}')
+ except ValueError as e:
+ assert str(e) == 'relativize needs an absolute path'
+
+class TestArbitraryZoiaFilesRelativize(_ATestArbitraryZoiaFiles,
+ _ATestRelativize):
+ """arbitrary_zoia_file should implement relativize correctly."""
+
+class TestSimpleStructureRelativize(_ATestSimpleStructure, _ATestRelativize):
+ """simple_structure should implement relativize correctly."""
diff --git a/src/utils.py b/src/utils.py
index 7b0f850..94598da 100644
--- a/src/utils.py
+++ b/src/utils.py
@@ -56,3 +56,13 @@ def dir_case_is_valid(dir_path: Path, rel_dir_path: Path,
raise_errors)
case_valid = False
return case_valid
+
+def valid_src_path(src_path: str):
+ """Returns True if the specified string path is valid as a src-relative
+ path."""
+ return src_path.lower() == src_path
+
+def valid_zoia_path(zoia_path: str):
+ """Returns True if the specified string path is valid as a src-relative
+ path to a Zoia file."""
+ return valid_src_path(zoia_path) and zoia_path.endswith('.zoia')
diff --git a/src/zoia_processor.py b/src/zoia_processor.py
index 6e4b70c..5640176 100644
--- a/src/zoia_processor.py
+++ b/src/zoia_processor.py
@@ -25,11 +25,13 @@
from pathlib import Path
from antlr4 import FileStream, InputStream, Token
+from antlr4.tree.Tree import ParseTree
-from parse_converter import ParseConverter
from ast_nodes import ZoiaFileNode
+from ast_validator import ASTValidator
from exception import ParsingError
from grammar import parse, SA_ErrorListener
+from parse_converter import ParseConverter
from src_pos import SourcePos
class _RaiseErrorListener(SA_ErrorListener):
@@ -54,19 +56,25 @@ def syntaxError(self, input_stream: InputStream, offending_symbol: Token,
# the middle of handling while this gets called
raise ParsingError(SourcePos(origin_file, line, column), msg) from None
+def _process_shared(parse_tree: ParseTree, src_name: str) -> ZoiaFileNode:
+ """Shared code of process_zoia_file and process_zoia_string."""
+ ret_ast = ParseConverter(src_name).visit(parse_tree)
+ ASTValidator().visit(ret_ast)
+ return ret_ast
+
def process_zoia_file(zoia_path: Path, project_folder: Path) -> ZoiaFileNode:
"""Parses the Zoia file at the specified path and converts it into a Zoia
- AST."""
+ AST. Also performs validation on the resulting AST."""
# UTF-8 required by specification, so this is fine
ins = FileStream(str(zoia_path), encoding='utf-8')
parse_tree = parse(ins, 'zoiaFile',
sa_err_listener=_RaiseErrorListener(project_folder))
- return ParseConverter(ins.fileName).visit(parse_tree)
+ return _process_shared(parse_tree, ins.fileName)
def process_zoia_string(zoia_src: str, src_name: str) -> ZoiaFileNode:
"""Parses the specified string representation of a Zoia file and converts
it into a Zoia AST. src_name specifies the name of the source to use in
- errors etc."""
+ errors etc. Also performs validation on the resulting AST."""
ins = InputStream(zoia_src)
parse_tree = parse(ins, 'zoiaFile', sa_err_listener=_RaiseErrorListener())
- return ParseConverter(src_name).visit(parse_tree)
+ return _process_shared(parse_tree, src_name)