- - Successful build #{{ build.number }} - - | - {{else}} -- - Failed build #{{ build.number }} - - | - {{/success}} -||||||||||
-
-
|
-
diff --git a/.dockerignore b/.dockerignore
index a49be61..f279409 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,9 +1,3 @@
-/.env
-/.gitignore
-/Docker*
-/DOCS.md
-/LICENSE
-/logo.svg
-/MAINTAINERS
-/publish.sh
-/README.md
+/Dockerfile
+/vendor
+/.git
diff --git a/.gitignore b/.gitignore
index 0c1a1fe..ea4fca0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,28 +1,3 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-*.test
-*.prof
-.env
-
-coverage.out
-woodpecker-email
+/vendor
+/.php-cs-fixer.cache
+/test*
diff --git a/.woodpecker.yml b/.woodpecker.yml
index c289a13..c81b729 100644
--- a/.woodpecker.yml
+++ b/.woodpecker.yml
@@ -1,11 +1,4 @@
steps:
- tests:
- image: golang:1.18
- commands:
- - test -n "$CI_COMMIT_TAG" && sed "s/{app_version}/$CI_COMMIT_TAG/g" -i main.go || true
- - test -n "$CI_COMMIT_SHA" && sed "s/{app_version}/${CI_COMMIT_SHA:0:7}/g" -i main.go || true
- - make test
-
build_push_latest_gitnet:
image: plugins/docker
secrets: [registry_user, registry_password]
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index fd2c079..0000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,11 +0,0 @@
-## [Unreleased]
-
-## 1.0.1-wp
-### Fixed
-* fix fatal error when the env var `CI_COMMIT_PULL_REQUEST` is empty (#2)
-
-## 1.0.0-wp
-### Added
-* add environment variables of woodpecker
-* add ci
-* add evaluate setting
diff --git a/DOCS.md b/DOCS.md
index 10af825..dd8afe2 100644
--- a/DOCS.md
+++ b/DOCS.md
@@ -1,5 +1,6 @@
---
name: Woodpecker Email
+author: Simon Vieille
icon: https://gitnet.fr/deblan/woodpecker-email/raw/branch/develop/logo.svg
description: plugin to send build status notifications via Email.
tags: [notifications, email]
@@ -8,165 +9,107 @@ containerImageUrl: https://hub.docker.com/r/deblan/woodpecker-email
url: https://gitnet.fr/deblan/woodpecker-email
---
-Use the Email plugin for sending build status notifications via email.
+## Settings
-## Config
-You can configure the plugin using the following parameters:
+| Settings Name | Required | Type | Description | Documentation |
+| --- | --- | --- | --- | --- |
+| dsn | yes | `string` | Mail transport configuration | [Documentation](https://symfony.com/doc/current/mailer.html#tls-peer-verification) |
+| from.address | yes | `string` | Email address of the sender | |
+| from.name | no | `0string` | Name of the sender | |
+| recipients | no | `string` or `list` | List of recipients to send this mail to (besides the commit author) | YAML list or comma separated list |
+| recipients_only | no | `boolean` | Exclude the committer | |
+| content.subject | no | `string` | Define the email subject template | |
+| content.body | no | `string` | Define the email body template | |
+| attachments | no | `string` or `list` | List of files to attach | YAML list or comma separated list |
-* **from.address** - Send notifications from this address
-* **from.name** - Notifications sender name
-* **host** - SMTP server host
-* **port** - SMTP server port, defaults to `587`
-* **username** - SMTP username
-* **password** - SMTP password
-* **skip_verify** - Skip verification of SSL certificates, defaults to `false`
-* **no_starttls** - Enable/Disable STARTTLS
-* **recipients** - List of recipients to send this mail to (besides the commit author)
-* **recipients_file** - Filename to load additional recipients from (textfile with one email per line) (besides the commit author)
-* **recipients_only** - Do not send mails to the commit author, but only to **recipients**, defaults to `false`
-* **subject** - The subject line template
-* **body** - The email body template
-* **attachment** - An optional file to attach to the sent mail(s), can be an absolute path or relative to the working directory.
-* **evaluate** - An optional expression to evaluate (on the fly) whether the mail should be sent or not ([https://woodpecker-ci.org/docs/next/usage/pipeline-syntax#evaluate](https://woodpecker-ci.org/docs/next/usage/pipeline-syntax#evaluate)).
-## Example
-The following is a sample configuration in your .woodpecker.yml file:
+### Example
-```yaml
-pipeline:
+
+```
+steps:
mail:
- image: deblan/woodpecker-email
+ image: deblan/woodpecker-email-php
settings:
- from.address: noreply@github.com
- from.name: John Smith
- host: smtp.mailgun.org
- username: octocat
- password: 12345
+ dsn: "smtp://username:password@mail.example.com:587?verify_peer=1"
+ from:
+ address: "woodpecker@example.com"
+ name: "Woodpecker"
+ evaluate: "build.status == 'failure' or prev_pipeline.status == 'failure'"
recipients:
- - octocat@github.com
+ - dev1@example.com
+ - dev2@example.com
+ recipients_only: false
+ content:
+ subject: "[{{ pipeline.status }}] {{ repo.full_name }} ({{ commit.branch }} - {{ commit.sha[0:8] }}"
+ body: |
+ {{ commit.sha }}
+ {{ pipeline.status }}
+ {{ commit.author_email }}
+ attachments:
+ - log/*
```
-### Secrets
-The Email plugin supports reading credentials and other parameters from the Drone secret store. This is strongly recommended instead of storing credentials in the pipeline configuration in plain text.
+### Evaluation and content
-```diff
-pipeline:
- mail:
- image: deblan/woodpecker-email
- settings:
- from.address: noreply@github.com
- host: smtp.mailgun.org
-+ username:
-+ from_secret: email_username
-+ password: 12345
-+ from_secret: email_password
- recipients:
- - octocat@github.com
-```
-
-### Evaluation
-
-This plugin introduces an optional expression to evaluate (on the fly) whether the mail should be sent or not.
+See the [Twig documentation](https://twig.symfony.com/doc/3.x/).
-```diff
-pipeline:
- mail:
- image: deblan/woodpecker-email
- settings:
- ...
- when:
- - evaluate: 'CI_STEP_STATUS == "failure" || CI_PREV_PIPELINE_STATUS == "failure"'
-```
+| Variable | Value |
+| --- | --- |
+| `workspace` | `CI_WORKSPACE` |
+| `repo.full_name` | `CI_REPO` |
+| `repo.owner` | `CI_REPO_OWNER` |
+| `repo.name` | `CI_REPO_NAME` |
+| `repo.url` | `CI_REPO_URL` |
+| `commit.sha` | `CI_COMMIT_SHA` |
+| `commit.ref` | `CI_COMMIT_REF` |
+| `commit.branch` | `CI_COMMIT_BRANCH` |
+| `commit.source_branch` | `CI_COMMIT_SOURCE_BRANCH` |
+| `commit.target_branch` | `CI_COMMIT_TARGET_BRANCH` |
+| `commit.tag` | `CI_COMMIT_TAG` |
+| `commit.pull_request` | `CI_COMMIT_PULL_REQUEST` |
+| `commit.pull_request_labels` | `CI_COMMIT_PULL_REQUEST_LABELS` |
+| `commit.message` | `CI_COMMIT_MESSAGE` |
+| `commit.author` | `CI_COMMIT_AUTHOR` |
+| `commit.author_email` | `CI_COMMIT_AUTHOR_EMAIL` |
+| `commit.author_avatar` | `CI_COMMIT_AUTHOR_AVATAR` |
+| `prev_commit.sha` | `CI_PREV_COMMIT_SHA` |
+| `prev_commit.ref` | `CI_PREV_COMMIT_REF` |
+| `prev_commit.branch` | `CI_PREV_COMMIT_BRANCH` |
+| `prev_commit.source_branch` | `CI_PREV_COMMIT_SOURCE_BRANCH` |
+| `prev_commit.target_branch` | `CI_PREV_COMMIT_TARGET_BRANCH` |
+| `prev_commit.message` | `CI_PREV_COMMIT_MESSAGE` |
+| `prev_commit.author` | `CI_PREV_COMMIT_AUTHOR` |
+| `prev_commit.author_email` | `CI_PREV_COMMIT_AUTHOR_EMAIL` |
+| `prev_commit.author_avatar` | `CI_PREV_COMMIT_AUTHOR_AVATAR` |
+| `prev_commit.url` | `CI_PREV_COMMIT_URL` |
+| `pipeline.number` | `CI_PIPELINE_NUMBER` |
+| `pipeline.parent` | `CI_PIPELINE_PARENT` |
+| `pipeline.event` | `CI_PIPELINE_EVENT` |
+| `pipeline.url` | `CI_PIPELINE_URL` |
+| `pipeline.deploy_target` | `CI_PIPELINE_DEPLOY_TARGET` |
+| `pipeline.status` | `CI_PIPELINE_STATUS` |
+| `pipeline.created_at` | `CI_PIPELINE_CREATED` |
+| `pipeline.stared_at` | `CI_PIPELINE_STARTED` |
+| `pipeline.finished_at` | `CI_PIPELINE_FINISHED` |
+| `prev_pipeline.number` | `CI_PREV_PIPELINE_NUMBER` |
+| `prev_pipeline.parent` | `CI_PREV_PIPELINE_PARENT` |
+| `prev_pipeline.event` | `CI_PREV_PIPELINE_EVENT` |
+| `prev_pipeline.url` | `CI_PREV_PIPELINE_URL` |
+| `prev_pipeline.deploy_target` | `CI_PREV_PIPELINE_DEPLOY_TARGET` |
+| `prev_pipeline.status` | `CI_PREV_PIPELINE_STATUS` |
+| `prev_pipeline.created_at` | `CI_PREV_PIPELINE_CREATED` |
+| `prev_pipeline.stared_at` | `CI_PREV_PIPELINE_STARTED` |
+| `prev_pipeline.finished_at` | `CI_PREV_PIPELINE_FINISHED` |
+| `workflow.name` | `WORKFLOW_NAME` |
+| `step.name` | `CI_STEP_NAME` |
+| `step.number` | `CI_STEP_NUMBER` |
+| `step.status` | `CI_STEP_STATUS` |
+| `step.start_at` | `CI_STEP_STARTED` |
+| `step.finished_at` | `CI_STEP_FINISHED` |
+| `step.url` | `CI_STEP_URL` |
-The problem is that the expression is evaluated before the pipeline is generated. In this case, `CI_STEP_STATUS` does not exist yet and the mail step is ignored unless the previous pipeline failed.
-
-```diff
-pipeline:
- mail:
- image: deblan/woodpecker-email
- settings:
- ...
-+ evaluate: 'CI_STEP_STATUS == "failure" || CI_PREV_PIPELINE_STATUS == "failure"'
- when:
-- - evaluate: 'CI_STEP_STATUS == "failure" || CI_PREV_PIPELINE_STATUS == "failure"'
-```
-
-More information about the syntaxe on ([https://woodpecker-ci.org/docs/next/usage/pipeline-syntax#evaluate](https://woodpecker-ci.org/docs/next/usage/pipeline-syntax#evaluate)).
-
-### Custom Templates
-
-In some cases you may want to customize the look and feel of the email message
-so you can use custom templates. For the use case we expose the following
-additional parameters, all of the accept a custom handlebars template, directly
-provided as a string or as a remote URL which gets fetched and parsed:
-
-* **subject** - A handlebars template to create a custom subject. For more
- details take a look at the [docs](http://handlebarsjs.com/). You can see the
- default template [here](https://github.com/Drillster/drone-email/blob/master/defaults.go#L14)
-* **body** - A handlebars template to create a custom template. For more
- details take a look at the [docs](http://handlebarsjs.com/). You can see the
- default template [here](https://github.com/Drillster/drone-email/blob/master/defaults.go#L19-L267)
-
-Example configuration that generate a custom email:
-
-```yaml
-pipeline:
- mail:
- image: deblan/woodpecker-email
- settings:
- from.address: noreply@github.com
- host: smtp.mailgun.org
- username: octocat
- password: 12345
- subject: >
- [{{ build.status }}]
- {{ repo.owner }}/{{ repo.name }}
- ({{ build.branch }} - {{ truncate build.commit 8 }})
- body:
- https://git.io/vgvPz
-```
-
-### Skip SSL verify
-
-In some cases you may want to skip SSL verification, even if we discourage that
-as it leads to an unsecure environment. Please use this option only within your
-intranet and/or with truested resources. For this use case we expose the
-following additional parameter:
-
-* **skip_verify** - Skip verification of SSL certificates
-
-Example configuration that skips SSL verification:
-
-```diff
-pipeline:
- mail:
- image: deblan/woodpecker-email
- settings:
- from: noreply@github.com
- host: smtp.mailgun.org
- username: octocat
- password: 12345
-+ skip_verify: true
-```
-
-### STARTTLS
-
-By default, STARTTLS is being used opportunistically meaning, if advertised
-by the server, traffic is going to be encrypted.
-
-You may want to disable STARTTLS, e.g., with faulty and/or internal servers:
-
-```diff
-pipeline:
- mail:
- image: deblan/woodpecker-email
- settings:
- from: noreply@github.com
- host: smtp.mailgun.org
- username: octocat
- password: 12345
-+ no_starttls: true
-```
+[dsn_doc]: https://symfony.com/doc/current/mailer.html#tls-peer-verification
diff --git a/Dockerfile b/Dockerfile
index b897037..f64aa72 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,10 +1,9 @@
-FROM golang:1.18
+FROM deblan/php:8.2
-WORKDIR /go/src/woodpecker-email
+WORKDIR /opt/app
COPY . .
-RUN apt-get update && apt-get -y install ca-certificates tzdata
-RUN make build && cp /go/src/woodpecker-email/woodpecker-email /bin
+RUN composer install
-ENTRYPOINT ["/bin/woodpecker-email"]
+ENTRYPOINT ["php", "/opt/app/bin/console"]
diff --git a/Dockerfile.armhf b/Dockerfile.armhf
deleted file mode 100644
index 7392d9a..0000000
--- a/Dockerfile.armhf
+++ /dev/null
@@ -1,13 +0,0 @@
-FROM golang:1.15-alpine as builder
-
-WORKDIR /go/src/drone-email
-COPY . .
-
-RUN GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0 go build
-
-FROM alpine:3.14
-
-RUN apk add --no-cache ca-certificates tzdata
-
-COPY --from=builder /go/src/drone-email/drone-email /bin/
-ENTRYPOINT ["/bin/drone-email"]
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 8dada3e..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "{}"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright {yyyy} {name of copyright owner}
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/MAINTAINERS b/MAINTAINERS
deleted file mode 100644
index fe583f2..0000000
--- a/MAINTAINERS
+++ /dev/null
@@ -1,51 +0,0 @@
-[people]
- [people.bradrydzewski]
- name = "Brad Rydzewski"
- email = "brad@drone.io"
- login = "bradrydzewski"
- [people.Bugagazavr]
- name = "Kirill"
- email = ""
- login = "Bugagazavr"
- [people.donny-dont]
- name = "Don Olmstead"
- email = "donny-dont@gmail.com"
- login = "donny-dont"
- [people.jackspirou]
- name = "Jack Spirou"
- email = ""
- login = "jackspirou"
- [people.msteinert]
- name = "Mike Steinert"
- email = ""
- login = "msteinert"
- [people.nlf]
- name = "Nathan LaFreniere"
- email = ""
- login = "nlf"
- [people.tboerger]
- name = "Thomas Boerger"
- email = "thomas@webhippie.de"
- login = "tboerger"
- [people.athieriot]
- name = "Aurélien Thieriot"
- email = "a.thieriot@gmail.com"
- login = "athieriot"
- [people.mjwwit]
- name = "Michael de Wit"
- email = "mjwwit@gmail.com"
- login = "mjwwit"
-
-[org]
- [org.core]
- people = [
- "bradrydzewski",
- "Bugagazavr",
- "donny-dont",
- "jackspirou",
- "msteinert",
- "nlf",
- "tboerger",
- "athieriot",
- "mjwwit"
- ]
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 183e2cb..0000000
--- a/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-all: test build
-
-test:
- go vet
- go test -cover -coverprofile=coverage.out
-
-build:
- GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build
diff --git a/README.md b/README.md
index d83331e..dc81636 100644
--- a/README.md
+++ b/README.md
@@ -1,52 +1,3 @@
-# woodpecker-email
+# woodpecker-email-php
Woodpecker plugin to send build status notifications via Email. For the usage information and a listing of the available options please take a look at [the docs](DOCS.md).
-
-## Binary
-
-Build the binary with the following command:
-
-```
-go build
-```
-
-## Docker
-
-Build the docker image with the following commands:
-
-```
-docker build -t deblan/woodpecker-email:latest .
-```
-
-This will create a Docker image called `deblan/woodpecker-email:latest`.
-Please note incorrectly building the image for the correct x64 linux and with GCO disabled will result in an error when running the Docker image:
-
-```
-docker: Error response from daemon: Container command
-'/bin/woodpecker-email' not found or does not exist..
-```
-
-### Example
-Execute from the working directory:
-
-```sh
-docker run --rm \
- -e PLUGIN_FROM.ADDRESS=drone@test.test \
- -e PLUGIN_FROM.NAME="John Smith" \
- -e PLUGIN_HOST=smtp.test.test \
- -e PLUGIN_USERNAME=drone \
- -e PLUGIN_PASSWORD=test \
- -e CI_REPO_OWNER=octocat \
- -e CI_REPO_NAME=hello-world \
- -e CI_COMMIT_SHA=7fd1a60b01f91b314f59955a4e4d4e80d8edf11d \
- -e CI_COMMIT_BRANCH=master \
- -e CI_COMMIT_AUTHOR=octocat \
- -e CI_COMMIT_AUTHOR_EMAIL=octocat@test.test \
- -e CI_BUILD_NUMBER=1 \
- -e CI_PIPELINE_STATUS=success \
- -e CI_PIPELINE_LINK=http://github.com/octocat/hello-world \
- -e CI_COMMIT_MESSAGE="Hello world!" \
- -v $(pwd):$(pwd) \
- -w $(pwd) \
- deblan/woodpecker-email
-```
diff --git a/bin/console b/bin/console
new file mode 100755
index 0000000..a4da810
--- /dev/null
+++ b/bin/console
@@ -0,0 +1,133 @@
+#!/usr/bin/php
+ 'CI_WORKSPACE',
+ 'repo' => [
+ 'full_name' => 'CI_REPO',
+ 'owner' => 'CI_REPO_OWNER',
+ 'name' => 'CI_REPO_NAME',
+ 'url' => 'CI_REPO_URL',
+ ],
+ 'commit' => [
+ 'sha' => 'CI_COMMIT_SHA',
+ 'ref' => 'CI_COMMIT_REF',
+ 'branch' => 'CI_COMMIT_BRANCH',
+ 'source_branch' => 'CI_COMMIT_SOURCE_BRANCH',
+ 'target_branch' => 'CI_COMMIT_TARGET_BRANCH',
+ 'tag' => 'CI_COMMIT_TAG',
+ 'pull_request' => 'CI_COMMIT_PULL_REQUEST',
+ 'pull_request_labels' => 'CI_COMMIT_PULL_REQUEST_LABELS',
+ 'tag' => 'CI_COMMIT_TAG',
+ 'message' => 'CI_COMMIT_MESSAGE',
+ 'author' => 'CI_COMMIT_AUTHOR',
+ 'author_email' => 'CI_COMMIT_AUTHOR_EMAIL',
+ 'author_avatar' => 'CI_COMMIT_AUTHOR_AVATAR',
+ ],
+ 'prev_commit' => [
+ 'sha' => 'CI_PREV_COMMIT_SHA',
+ 'ref' => 'CI_PREV_COMMIT_REF',
+ 'branch' => 'CI_PREV_COMMIT_BRANCH',
+ 'source_branch' => 'CI_PREV_COMMIT_SOURCE_BRANCH',
+ 'target_branch' => 'CI_PREV_COMMIT_TARGET_BRANCH',
+ 'message' => 'CI_PREV_COMMIT_MESSAGE',
+ 'author' => 'CI_PREV_COMMIT_AUTHOR',
+ 'author_email' => 'CI_PREV_COMMIT_AUTHOR_EMAIL',
+ 'author_avatar' => 'CI_PREV_COMMIT_AUTHOR_AVATAR',
+ 'url' => 'CI_PREV_COMMIT_URL',
+ ],
+ 'pipeline' => [
+ 'number' => 'CI_PIPELINE_NUMBER',
+ 'parent' => 'CI_PIPELINE_PARENT',
+ 'event' => 'CI_PIPELINE_EVENT',
+ 'url' => 'CI_PIPELINE_URL',
+ 'deploy_target' => 'CI_PIPELINE_DEPLOY_TARGET',
+ 'status' => 'CI_PIPELINE_STATUS',
+ 'created_at' => 'CI_PIPELINE_CREATED',
+ 'stared_at' => 'CI_PIPELINE_STARTED',
+ 'finished_at' => 'CI_PIPELINE_FINISHED',
+ ],
+ 'prev_pipeline' => [
+ 'number' => 'CI_PREV_PIPELINE_NUMBER',
+ 'parent' => 'CI_PREV_PIPELINE_PARENT',
+ 'event' => 'CI_PREV_PIPELINE_EVENT',
+ 'url' => 'CI_PREV_PIPELINE_URL',
+ 'deploy_target' => 'CI_PREV_PIPELINE_DEPLOY_TARGET',
+ 'status' => 'CI_PREV_PIPELINE_STATUS',
+ 'created_at' => 'CI_PREV_PIPELINE_CREATED',
+ 'stared_at' => 'CI_PREV_PIPELINE_STARTED',
+ 'finished_at' => 'CI_PREV_PIPELINE_FINISHED',
+ ],
+ 'workflow' => [
+ 'name' => 'WORKFLOW_NAME',
+ ],
+ 'step' => [
+ 'name' => 'CI_STEP_NAME',
+ 'number' => 'CI_STEP_NUMBER',
+ 'status' => 'CI_STEP_STATUS',
+ 'start_at' => 'CI_STEP_STARTED',
+ 'finished_at' => 'CI_STEP_FINISHED',
+ 'url' => 'CI_STEP_URL',
+ ],
+]);
+
+$config = EnvVarLoader::buildArray([
+ 'dsn' => 'PLUGIN_DSN',
+ 'from' => 'PLUGIN_FROM',
+ 'recipients' => 'PLUGIN_RECIPIENTS',
+ 'is_recipients_only' => 'PLUGIN_RECIPIENTS_ONLY',
+ 'attachments' => 'PLUGIN_ATTACHMENTS',
+ 'evaluate' => 'PLUGIN_EVALUATE',
+ 'content' => 'PLUGIN_CONTENT',
+], [
+ 'PLUGIN_RECIPIENTS_ONLY' => true,
+]);
+
+function writeln(...$values)
+{
+ foreach ($values as $value) {
+ echo sprintf("%s\n", $value);
+ }
+}
+
+function handleError($section, Exception $e)
+{
+ writeln(
+ sprintf('ERROR - %s', $section),
+ $e->getMessage()
+ );
+
+ exit(1);
+}
+
+$twig = (new TwigFactory())->create();
+$emailFactory = new EmailFactory($twig, $config, $build);
+$evaluation = new Evaluation($twig);
+
+try {
+ if (!empty($config['evaluate']) && !$evaluation->isTrue($config['evaluate'], $build)) {
+ writeln('Evaluation returns false.', 'Program aborted!');
+ } else {
+ $emailFactory
+ ->createMailer($config)
+ ->send($emailFactory->createEmail($config, $build))
+ ;
+
+ writeln('Email sent!');
+ }
+} catch (SyntaxError $e) {
+ handleError('Syntax error', $e);
+} catch (TransportException $e) {
+ handleError('Transport error', $e);
+} catch (\Exception $e) {
+ handleError('Generic error', $e);
+}
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..e47702c
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,11 @@
+{
+ "autoload": {
+ "psr-4": {
+ "Plugin\\": "src/"
+ }
+ },
+ "require": {
+ "symfony/mailer": "^7.0",
+ "twig/twig": "^3.8"
+ }
+}
diff --git a/defaults.go b/defaults.go
deleted file mode 100644
index 3643145..0000000
--- a/defaults.go
+++ /dev/null
@@ -1,270 +0,0 @@
-package main
-
-const (
- // DefaultPort is the default SMTP port to use
- DefaultPort = 587
- // DefaultOnlyRecipients controls wether to exclude the commit author by default
- DefaultOnlyRecipients = false
- // DefaultSkipVerify controls wether to skip SSL verification for the SMTP server
- DefaultSkipVerify = false
- // DefaultClientHostname is the client hostname used in the HELO command sent to the SMTP server
- DefaultClientHostname = "localhost"
-)
-
-// DefaultSubject is the default subject template to use for the email
-const DefaultSubject = `
-[{{ build.status }}] {{ repo.owner }}/{{ repo.name }} ({{ commit.branch }} - {{ truncate commit.sha 8 }})
-`
-
-// DefaultTemplate is the default body template to use for the email
-const DefaultTemplate = `
-
-
-
- |
-
-
-
|
- - |
+ |
+
+
+
|
+ + |
- -
- - -## Who is using Expr? - -* [Aviasales](https://aviasales.ru) are actively using Expr for different parts of the search engine. -* [Argo Rollouts](https://argoproj.github.io/argo-rollouts/) - Progressive Delivery for Kubernetes. -* [Argo Workflows](https://argoproj.github.io/argo/) - The workflow engine for KubernetesOverview. -* [Crowdsec](https://crowdsec.net/) - A security automation tool. -* [Mystery Minds](https://www.mysteryminds.com/en/) uses Expr to allow easy yet powerful customization of its matching algorithm. -* [qiniu](https://www.qiniu.com/) qiniu cloud use Expr in trade systems. - -[Add your company too](https://github.com/antonmedv/expr/edit/master/README.md) - -## License - -[MIT](LICENSE) diff --git a/vendor/github.com/antonmedv/expr/ast/node.go b/vendor/github.com/antonmedv/expr/ast/node.go deleted file mode 100644 index 4b2b5c2..0000000 --- a/vendor/github.com/antonmedv/expr/ast/node.go +++ /dev/null @@ -1,171 +0,0 @@ -package ast - -import ( - "reflect" - "regexp" - - "github.com/antonmedv/expr/file" -) - -// Node represents items of abstract syntax tree. -type Node interface { - Location() file.Location - SetLocation(file.Location) - Type() reflect.Type - SetType(reflect.Type) -} - -func Patch(node *Node, newNode Node) { - newNode.SetType((*node).Type()) - newNode.SetLocation((*node).Location()) - *node = newNode -} - -type base struct { - loc file.Location - nodeType reflect.Type -} - -func (n *base) Location() file.Location { - return n.loc -} - -func (n *base) SetLocation(loc file.Location) { - n.loc = loc -} - -func (n *base) Type() reflect.Type { - return n.nodeType -} - -func (n *base) SetType(t reflect.Type) { - n.nodeType = t -} - -type NilNode struct { - base -} - -type IdentifierNode struct { - base - Value string - NilSafe bool -} - -type IntegerNode struct { - base - Value int -} - -type FloatNode struct { - base - Value float64 -} - -type BoolNode struct { - base - Value bool -} - -type StringNode struct { - base - Value string -} - -type ConstantNode struct { - base - Value interface{} -} - -type UnaryNode struct { - base - Operator string - Node Node -} - -type BinaryNode struct { - base - Operator string - Left Node - Right Node -} - -type MatchesNode struct { - base - Regexp *regexp.Regexp - Left Node - Right Node -} - -type PropertyNode struct { - base - Node Node - Property string - NilSafe bool -} - -type IndexNode struct { - base - Node Node - Index Node -} - -type SliceNode struct { - base - Node Node - From Node - To Node -} - -type MethodNode struct { - base - Node Node - Method string - Arguments []Node - NilSafe bool -} - -type FunctionNode struct { - base - Name string - Arguments []Node - Fast bool -} - -type BuiltinNode struct { - base - Name string - Arguments []Node -} - -type ClosureNode struct { - base - Node Node -} - -type PointerNode struct { - base -} - -type ConditionalNode struct { - base - Cond Node - Exp1 Node - Exp2 Node -} - -type ArrayNode struct { - base - Nodes []Node -} - -type MapNode struct { - base - Pairs []Node -} - -type PairNode struct { - base - Key Node - Value Node -} diff --git a/vendor/github.com/antonmedv/expr/ast/print.go b/vendor/github.com/antonmedv/expr/ast/print.go deleted file mode 100644 index 285984b..0000000 --- a/vendor/github.com/antonmedv/expr/ast/print.go +++ /dev/null @@ -1,59 +0,0 @@ -package ast - -import ( - "fmt" - "reflect" - "regexp" -) - -func Dump(node Node) string { - return dump(reflect.ValueOf(node), "") -} - -func dump(v reflect.Value, ident string) string { - if !v.IsValid() { - return "nil" - } - t := v.Type() - switch t.Kind() { - case reflect.Struct: - out := t.Name() + "{\n" - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - if isPrivate(f.Name) { - continue - } - s := v.Field(i) - out += fmt.Sprintf("%v%v: %v,\n", ident+"\t", f.Name, dump(s, ident+"\t")) - } - return out + ident + "}" - case reflect.Slice: - if v.Len() == 0 { - return "[]" - } - out := "[\n" - for i := 0; i < v.Len(); i++ { - s := v.Index(i) - out += fmt.Sprintf("%v%v,", ident+"\t", dump(s, ident+"\t")) - if i+1 < v.Len() { - out += "\n" - } - } - return out + "\n" + ident + "]" - case reflect.Ptr: - return dump(v.Elem(), ident) - case reflect.Interface: - return dump(reflect.ValueOf(v.Interface()), ident) - - case reflect.String: - return fmt.Sprintf("%q", v) - default: - return fmt.Sprintf("%v", v) - } -} - -var isCapital = regexp.MustCompile("^[A-Z]") - -func isPrivate(s string) bool { - return !isCapital.Match([]byte(s)) -} diff --git a/vendor/github.com/antonmedv/expr/ast/visitor.go b/vendor/github.com/antonmedv/expr/ast/visitor.go deleted file mode 100644 index a3e270e..0000000 --- a/vendor/github.com/antonmedv/expr/ast/visitor.go +++ /dev/null @@ -1,108 +0,0 @@ -package ast - -import "fmt" - -type Visitor interface { - Enter(node *Node) - Exit(node *Node) -} - -type walker struct { - visitor Visitor -} - -func Walk(node *Node, visitor Visitor) { - w := walker{ - visitor: visitor, - } - w.walk(node) -} - -func (w *walker) walk(node *Node) { - w.visitor.Enter(node) - - switch n := (*node).(type) { - case *NilNode: - w.visitor.Exit(node) - case *IdentifierNode: - w.visitor.Exit(node) - case *IntegerNode: - w.visitor.Exit(node) - case *FloatNode: - w.visitor.Exit(node) - case *BoolNode: - w.visitor.Exit(node) - case *StringNode: - w.visitor.Exit(node) - case *ConstantNode: - w.visitor.Exit(node) - case *UnaryNode: - w.walk(&n.Node) - w.visitor.Exit(node) - case *BinaryNode: - w.walk(&n.Left) - w.walk(&n.Right) - w.visitor.Exit(node) - case *MatchesNode: - w.walk(&n.Left) - w.walk(&n.Right) - w.visitor.Exit(node) - case *PropertyNode: - w.walk(&n.Node) - w.visitor.Exit(node) - case *IndexNode: - w.walk(&n.Node) - w.walk(&n.Index) - w.visitor.Exit(node) - case *SliceNode: - if n.From != nil { - w.walk(&n.From) - } - if n.To != nil { - w.walk(&n.To) - } - w.visitor.Exit(node) - case *MethodNode: - w.walk(&n.Node) - for i := range n.Arguments { - w.walk(&n.Arguments[i]) - } - w.visitor.Exit(node) - case *FunctionNode: - for i := range n.Arguments { - w.walk(&n.Arguments[i]) - } - w.visitor.Exit(node) - case *BuiltinNode: - for i := range n.Arguments { - w.walk(&n.Arguments[i]) - } - w.visitor.Exit(node) - case *ClosureNode: - w.walk(&n.Node) - w.visitor.Exit(node) - case *PointerNode: - w.visitor.Exit(node) - case *ConditionalNode: - w.walk(&n.Cond) - w.walk(&n.Exp1) - w.walk(&n.Exp2) - w.visitor.Exit(node) - case *ArrayNode: - for i := range n.Nodes { - w.walk(&n.Nodes[i]) - } - w.visitor.Exit(node) - case *MapNode: - for i := range n.Pairs { - w.walk(&n.Pairs[i]) - } - w.visitor.Exit(node) - case *PairNode: - w.walk(&n.Key) - w.walk(&n.Value) - w.visitor.Exit(node) - default: - panic(fmt.Sprintf("undefined node type (%T)", node)) - } -} diff --git a/vendor/github.com/antonmedv/expr/checker/checker.go b/vendor/github.com/antonmedv/expr/checker/checker.go deleted file mode 100644 index 282031a..0000000 --- a/vendor/github.com/antonmedv/expr/checker/checker.go +++ /dev/null @@ -1,615 +0,0 @@ -package checker - -import ( - "fmt" - "reflect" - - "github.com/antonmedv/expr/ast" - "github.com/antonmedv/expr/conf" - "github.com/antonmedv/expr/file" - "github.com/antonmedv/expr/parser" -) - -var errorType = reflect.TypeOf((*error)(nil)).Elem() - -func Check(tree *parser.Tree, config *conf.Config) (reflect.Type, error) { - v := &visitor{ - collections: make([]reflect.Type, 0), - } - if config != nil { - v.types = config.Types - v.operators = config.Operators - v.expect = config.Expect - v.strict = config.Strict - v.defaultType = config.DefaultType - } - - t := v.visit(tree.Node) - - if v.expect != reflect.Invalid { - switch v.expect { - case reflect.Int64, reflect.Float64: - if !isNumber(t) { - return nil, fmt.Errorf("expected %v, but got %v", v.expect, t) - } - default: - if t.Kind() != v.expect { - return nil, fmt.Errorf("expected %v, but got %v", v.expect, t) - } - } - } - - if v.err != nil { - return t, v.err.Bind(tree.Source) - } - - return t, nil -} - -type visitor struct { - types conf.TypesTable - operators conf.OperatorsTable - expect reflect.Kind - collections []reflect.Type - strict bool - defaultType reflect.Type - err *file.Error -} - -func (v *visitor) visit(node ast.Node) reflect.Type { - var t reflect.Type - switch n := node.(type) { - case *ast.NilNode: - t = v.NilNode(n) - case *ast.IdentifierNode: - t = v.IdentifierNode(n) - case *ast.IntegerNode: - t = v.IntegerNode(n) - case *ast.FloatNode: - t = v.FloatNode(n) - case *ast.BoolNode: - t = v.BoolNode(n) - case *ast.StringNode: - t = v.StringNode(n) - case *ast.ConstantNode: - t = v.ConstantNode(n) - case *ast.UnaryNode: - t = v.UnaryNode(n) - case *ast.BinaryNode: - t = v.BinaryNode(n) - case *ast.MatchesNode: - t = v.MatchesNode(n) - case *ast.PropertyNode: - t = v.PropertyNode(n) - case *ast.IndexNode: - t = v.IndexNode(n) - case *ast.SliceNode: - t = v.SliceNode(n) - case *ast.MethodNode: - t = v.MethodNode(n) - case *ast.FunctionNode: - t = v.FunctionNode(n) - case *ast.BuiltinNode: - t = v.BuiltinNode(n) - case *ast.ClosureNode: - t = v.ClosureNode(n) - case *ast.PointerNode: - t = v.PointerNode(n) - case *ast.ConditionalNode: - t = v.ConditionalNode(n) - case *ast.ArrayNode: - t = v.ArrayNode(n) - case *ast.MapNode: - t = v.MapNode(n) - case *ast.PairNode: - t = v.PairNode(n) - default: - panic(fmt.Sprintf("undefined node type (%T)", node)) - } - node.SetType(t) - return t -} - -func (v *visitor) error(node ast.Node, format string, args ...interface{}) reflect.Type { - if v.err == nil { // show first error - v.err = &file.Error{ - Location: node.Location(), - Message: fmt.Sprintf(format, args...), - } - } - return interfaceType // interface represent undefined type -} - -func (v *visitor) NilNode(*ast.NilNode) reflect.Type { - return nilType -} - -func (v *visitor) IdentifierNode(node *ast.IdentifierNode) reflect.Type { - if v.types == nil { - return interfaceType - } - if t, ok := v.types[node.Value]; ok { - if t.Ambiguous { - return v.error(node, "ambiguous identifier %v", node.Value) - } - return t.Type - } - if !v.strict { - if v.defaultType != nil { - return v.defaultType - } - return interfaceType - } - if !node.NilSafe { - return v.error(node, "unknown name %v", node.Value) - } - return nilType -} - -func (v *visitor) IntegerNode(*ast.IntegerNode) reflect.Type { - return integerType -} - -func (v *visitor) FloatNode(*ast.FloatNode) reflect.Type { - return floatType -} - -func (v *visitor) BoolNode(*ast.BoolNode) reflect.Type { - return boolType -} - -func (v *visitor) StringNode(*ast.StringNode) reflect.Type { - return stringType -} - -func (v *visitor) ConstantNode(node *ast.ConstantNode) reflect.Type { - return reflect.TypeOf(node.Value) -} - -func (v *visitor) UnaryNode(node *ast.UnaryNode) reflect.Type { - t := v.visit(node.Node) - - switch node.Operator { - - case "!", "not": - if isBool(t) { - return boolType - } - - case "+", "-": - if isNumber(t) { - return t - } - - default: - return v.error(node, "unknown operator (%v)", node.Operator) - } - - return v.error(node, `invalid operation: %v (mismatched type %v)`, node.Operator, t) -} - -func (v *visitor) BinaryNode(node *ast.BinaryNode) reflect.Type { - l := v.visit(node.Left) - r := v.visit(node.Right) - - // check operator overloading - if fns, ok := v.operators[node.Operator]; ok { - t, _, ok := conf.FindSuitableOperatorOverload(fns, v.types, l, r) - if ok { - return t - } - } - - switch node.Operator { - case "==", "!=": - if isNumber(l) && isNumber(r) { - return boolType - } - if isComparable(l, r) { - return boolType - } - - case "or", "||", "and", "&&": - if isBool(l) && isBool(r) { - return boolType - } - - case "in", "not in": - if isString(l) && isStruct(r) { - return boolType - } - if isMap(r) { - return boolType - } - if isArray(r) { - return boolType - } - - case "<", ">", ">=", "<=": - if isNumber(l) && isNumber(r) { - return boolType - } - if isString(l) && isString(r) { - return boolType - } - - case "/", "-", "*": - if isNumber(l) && isNumber(r) { - return combined(l, r) - } - - case "**": - if isNumber(l) && isNumber(r) { - return floatType - } - - case "%": - if isInteger(l) && isInteger(r) { - return combined(l, r) - } - - case "+": - if isNumber(l) && isNumber(r) { - return combined(l, r) - } - if isString(l) && isString(r) { - return stringType - } - - case "contains", "startsWith", "endsWith": - if isString(l) && isString(r) { - return boolType - } - - case "..": - if isInteger(l) && isInteger(r) { - return reflect.SliceOf(integerType) - } - - default: - return v.error(node, "unknown operator (%v)", node.Operator) - - } - - return v.error(node, `invalid operation: %v (mismatched types %v and %v)`, node.Operator, l, r) -} - -func (v *visitor) MatchesNode(node *ast.MatchesNode) reflect.Type { - l := v.visit(node.Left) - r := v.visit(node.Right) - - if isString(l) && isString(r) { - return boolType - } - - return v.error(node, `invalid operation: matches (mismatched types %v and %v)`, l, r) -} - -func (v *visitor) PropertyNode(node *ast.PropertyNode) reflect.Type { - t := v.visit(node.Node) - if t, ok := fieldType(t, node.Property); ok { - return t - } - if !node.NilSafe { - return v.error(node, "type %v has no field %v", t, node.Property) - } - return nil -} - -func (v *visitor) IndexNode(node *ast.IndexNode) reflect.Type { - t := v.visit(node.Node) - i := v.visit(node.Index) - - if t, ok := indexType(t); ok { - if !isInteger(i) && !isString(i) { - return v.error(node, "invalid operation: cannot use %v as index to %v", i, t) - } - return t - } - - return v.error(node, "invalid operation: type %v does not support indexing", t) -} - -func (v *visitor) SliceNode(node *ast.SliceNode) reflect.Type { - t := v.visit(node.Node) - - _, isIndex := indexType(t) - - if isIndex || isString(t) { - if node.From != nil { - from := v.visit(node.From) - if !isInteger(from) { - return v.error(node.From, "invalid operation: non-integer slice index %v", from) - } - } - if node.To != nil { - to := v.visit(node.To) - if !isInteger(to) { - return v.error(node.To, "invalid operation: non-integer slice index %v", to) - } - } - return t - } - - return v.error(node, "invalid operation: cannot slice %v", t) -} - -func (v *visitor) FunctionNode(node *ast.FunctionNode) reflect.Type { - if f, ok := v.types[node.Name]; ok { - if fn, ok := isFuncType(f.Type); ok { - - inputParamsCount := 1 // for functions - if f.Method { - inputParamsCount = 2 // for methods - } - - if !isInterface(fn) && - fn.IsVariadic() && - fn.NumIn() == inputParamsCount && - ((fn.NumOut() == 1 && // Function with one return value - fn.Out(0).Kind() == reflect.Interface) || - (fn.NumOut() == 2 && // Function with one return value and an error - fn.Out(0).Kind() == reflect.Interface && - fn.Out(1) == errorType)) { - rest := fn.In(fn.NumIn() - 1) // function has only one param for functions and two for methods - if rest.Kind() == reflect.Slice && rest.Elem().Kind() == reflect.Interface { - node.Fast = true - } - } - - return v.checkFunc(fn, f.Method, node, node.Name, node.Arguments) - } - } - if !v.strict { - if v.defaultType != nil { - return v.defaultType - } - return interfaceType - } - return v.error(node, "unknown func %v", node.Name) -} - -func (v *visitor) MethodNode(node *ast.MethodNode) reflect.Type { - t := v.visit(node.Node) - if f, method, ok := methodType(t, node.Method); ok { - if fn, ok := isFuncType(f); ok { - return v.checkFunc(fn, method, node, node.Method, node.Arguments) - } - } - if !node.NilSafe { - return v.error(node, "type %v has no method %v", t, node.Method) - } - return nil -} - -// checkFunc checks func arguments and returns "return type" of func or method. -func (v *visitor) checkFunc(fn reflect.Type, method bool, node ast.Node, name string, arguments []ast.Node) reflect.Type { - if isInterface(fn) { - return interfaceType - } - - if fn.NumOut() == 0 { - return v.error(node, "func %v doesn't return value", name) - } - if numOut := fn.NumOut(); numOut > 2 { - return v.error(node, "func %v returns more then two values", name) - } - - numIn := fn.NumIn() - - // If func is method on an env, first argument should be a receiver, - // and actual arguments less then numIn by one. - if method { - numIn-- - } - - if fn.IsVariadic() { - if len(arguments) < numIn-1 { - return v.error(node, "not enough arguments to call %v", name) - } - } else { - if len(arguments) > numIn { - return v.error(node, "too many arguments to call %v", name) - } - if len(arguments) < numIn { - return v.error(node, "not enough arguments to call %v", name) - } - } - - offset := 0 - - // Skip first argument in case of the receiver. - if method { - offset = 1 - } - - for i, arg := range arguments { - t := v.visit(arg) - - var in reflect.Type - if fn.IsVariadic() && i >= numIn-1 { - // For variadic arguments fn(xs ...int), go replaces type of xs (int) with ([]int). - // As we compare arguments one by one, we need underling type. - in = fn.In(fn.NumIn() - 1) - in, _ = indexType(in) - } else { - in = fn.In(i + offset) - } - - if isIntegerOrArithmeticOperation(arg) { - t = in - setTypeForIntegers(arg, t) - } - - if t == nil { - continue - } - - if !t.AssignableTo(in) && t.Kind() != reflect.Interface { - return v.error(arg, "cannot use %v as argument (type %v) to call %v ", t, in, name) - } - } - - return fn.Out(0) -} - -func (v *visitor) BuiltinNode(node *ast.BuiltinNode) reflect.Type { - switch node.Name { - - case "len": - param := v.visit(node.Arguments[0]) - if isArray(param) || isMap(param) || isString(param) { - return integerType - } - return v.error(node, "invalid argument for len (type %v)", param) - - case "all", "none", "any", "one": - collection := v.visit(node.Arguments[0]) - if !isArray(collection) { - return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection) - } - - v.collections = append(v.collections, collection) - closure := v.visit(node.Arguments[1]) - v.collections = v.collections[:len(v.collections)-1] - - if isFunc(closure) && - closure.NumOut() == 1 && - closure.NumIn() == 1 && isInterface(closure.In(0)) { - - if !isBool(closure.Out(0)) { - return v.error(node.Arguments[1], "closure should return boolean (got %v)", closure.Out(0).String()) - } - return boolType - } - return v.error(node.Arguments[1], "closure should has one input and one output param") - - case "filter": - collection := v.visit(node.Arguments[0]) - if !isArray(collection) { - return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection) - } - - v.collections = append(v.collections, collection) - closure := v.visit(node.Arguments[1]) - v.collections = v.collections[:len(v.collections)-1] - - if isFunc(closure) && - closure.NumOut() == 1 && - closure.NumIn() == 1 && isInterface(closure.In(0)) { - - if !isBool(closure.Out(0)) { - return v.error(node.Arguments[1], "closure should return boolean (got %v)", closure.Out(0).String()) - } - if isInterface(collection) { - return arrayType - } - return reflect.SliceOf(collection.Elem()) - } - return v.error(node.Arguments[1], "closure should has one input and one output param") - - case "map": - collection := v.visit(node.Arguments[0]) - if !isArray(collection) { - return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection) - } - - v.collections = append(v.collections, collection) - closure := v.visit(node.Arguments[1]) - v.collections = v.collections[:len(v.collections)-1] - - if isFunc(closure) && - closure.NumOut() == 1 && - closure.NumIn() == 1 && isInterface(closure.In(0)) { - - return reflect.SliceOf(closure.Out(0)) - } - return v.error(node.Arguments[1], "closure should has one input and one output param") - - case "count": - collection := v.visit(node.Arguments[0]) - if !isArray(collection) { - return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection) - } - - v.collections = append(v.collections, collection) - closure := v.visit(node.Arguments[1]) - v.collections = v.collections[:len(v.collections)-1] - - if isFunc(closure) && - closure.NumOut() == 1 && - closure.NumIn() == 1 && isInterface(closure.In(0)) { - if !isBool(closure.Out(0)) { - return v.error(node.Arguments[1], "closure should return boolean (got %v)", closure.Out(0).String()) - } - - return integerType - } - return v.error(node.Arguments[1], "closure should has one input and one output param") - - default: - return v.error(node, "unknown builtin %v", node.Name) - } -} - -func (v *visitor) ClosureNode(node *ast.ClosureNode) reflect.Type { - t := v.visit(node.Node) - return reflect.FuncOf([]reflect.Type{interfaceType}, []reflect.Type{t}, false) -} - -func (v *visitor) PointerNode(node *ast.PointerNode) reflect.Type { - if len(v.collections) == 0 { - return v.error(node, "cannot use pointer accessor outside closure") - } - - collection := v.collections[len(v.collections)-1] - - if t, ok := indexType(collection); ok { - return t - } - return v.error(node, "cannot use %v as array", collection) -} - -func (v *visitor) ConditionalNode(node *ast.ConditionalNode) reflect.Type { - c := v.visit(node.Cond) - if !isBool(c) { - return v.error(node.Cond, "non-bool expression (type %v) used as condition", c) - } - - t1 := v.visit(node.Exp1) - t2 := v.visit(node.Exp2) - - if t1 == nil && t2 != nil { - return t2 - } - if t1 != nil && t2 == nil { - return t1 - } - if t1 == nil && t2 == nil { - return nilType - } - if t1.AssignableTo(t2) { - return t1 - } - return interfaceType -} - -func (v *visitor) ArrayNode(node *ast.ArrayNode) reflect.Type { - for _, node := range node.Nodes { - _ = v.visit(node) - } - return arrayType -} - -func (v *visitor) MapNode(node *ast.MapNode) reflect.Type { - for _, pair := range node.Pairs { - v.visit(pair) - } - return mapType -} - -func (v *visitor) PairNode(node *ast.PairNode) reflect.Type { - v.visit(node.Key) - v.visit(node.Value) - return nilType -} diff --git a/vendor/github.com/antonmedv/expr/checker/types.go b/vendor/github.com/antonmedv/expr/checker/types.go deleted file mode 100644 index 756ed8f..0000000 --- a/vendor/github.com/antonmedv/expr/checker/types.go +++ /dev/null @@ -1,349 +0,0 @@ -package checker - -import ( - "reflect" - - "github.com/antonmedv/expr/ast" -) - -var ( - nilType = reflect.TypeOf(nil) - boolType = reflect.TypeOf(true) - integerType = reflect.TypeOf(int(0)) - floatType = reflect.TypeOf(float64(0)) - stringType = reflect.TypeOf("") - arrayType = reflect.TypeOf([]interface{}{}) - mapType = reflect.TypeOf(map[string]interface{}{}) - interfaceType = reflect.TypeOf(new(interface{})).Elem() -) - -func typeWeight(t reflect.Type) int { - switch t.Kind() { - case reflect.Uint: - return 1 - case reflect.Uint8: - return 2 - case reflect.Uint16: - return 3 - case reflect.Uint32: - return 4 - case reflect.Uint64: - return 5 - case reflect.Int: - return 6 - case reflect.Int8: - return 7 - case reflect.Int16: - return 8 - case reflect.Int32: - return 9 - case reflect.Int64: - return 10 - case reflect.Float32: - return 11 - case reflect.Float64: - return 12 - default: - return 0 - } -} - -func combined(a, b reflect.Type) reflect.Type { - if typeWeight(a) > typeWeight(b) { - return a - } else { - return b - } -} - -func dereference(t reflect.Type) reflect.Type { - if t == nil { - return nil - } - if t.Kind() == reflect.Ptr { - t = dereference(t.Elem()) - } - return t -} - -func isComparable(l, r reflect.Type) bool { - l = dereference(l) - r = dereference(r) - - if l == nil || r == nil { // It is possible to compare with nil. - return true - } - if l.Kind() == r.Kind() { - return true - } - if isInterface(l) || isInterface(r) { - return true - } - return false -} - -func isInterface(t reflect.Type) bool { - t = dereference(t) - if t != nil { - switch t.Kind() { - case reflect.Interface: - return true - } - } - return false -} - -func isInteger(t reflect.Type) bool { - t = dereference(t) - if t != nil { - switch t.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - fallthrough - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return true - case reflect.Interface: - return true - } - } - return false -} - -func isFloat(t reflect.Type) bool { - t = dereference(t) - if t != nil { - switch t.Kind() { - case reflect.Float32, reflect.Float64: - return true - case reflect.Interface: - return true - } - } - return false -} - -func isNumber(t reflect.Type) bool { - return isInteger(t) || isFloat(t) -} - -func isBool(t reflect.Type) bool { - t = dereference(t) - if t != nil { - switch t.Kind() { - case reflect.Bool: - return true - case reflect.Interface: - return true - } - } - return false -} - -func isString(t reflect.Type) bool { - t = dereference(t) - if t != nil { - switch t.Kind() { - case reflect.String: - return true - case reflect.Interface: - return true - } - } - return false -} - -func isArray(t reflect.Type) bool { - t = dereference(t) - if t != nil { - switch t.Kind() { - case reflect.Slice, reflect.Array: - return true - case reflect.Interface: - return true - } - } - return false -} - -func isMap(t reflect.Type) bool { - t = dereference(t) - if t != nil { - switch t.Kind() { - case reflect.Map: - return true - case reflect.Interface: - return true - } - } - return false -} - -func isStruct(t reflect.Type) bool { - t = dereference(t) - if t != nil { - switch t.Kind() { - case reflect.Struct: - return true - } - } - return false -} - -func isFunc(t reflect.Type) bool { - t = dereference(t) - if t != nil { - switch t.Kind() { - case reflect.Func: - return true - } - } - return false -} - -func fieldType(ntype reflect.Type, name string) (reflect.Type, bool) { - ntype = dereference(ntype) - if ntype != nil { - switch ntype.Kind() { - case reflect.Interface: - return interfaceType, true - case reflect.Struct: - // First check all struct's fields. - for i := 0; i < ntype.NumField(); i++ { - f := ntype.Field(i) - if f.Name == name { - return f.Type, true - } - } - - // Second check fields of embedded structs. - for i := 0; i < ntype.NumField(); i++ { - f := ntype.Field(i) - if f.Anonymous { - if t, ok := fieldType(f.Type, name); ok { - return t, true - } - } - } - case reflect.Map: - return ntype.Elem(), true - } - } - - return nil, false -} - -func methodType(t reflect.Type, name string) (reflect.Type, bool, bool) { - if t != nil { - // First, check methods defined on type itself, - // independent of which type it is. - if m, ok := t.MethodByName(name); ok { - if t.Kind() == reflect.Interface { - // In case of interface type method will not have a receiver, - // and to prevent checker decreasing numbers of in arguments - // return method type as not method (second argument is false). - return m.Type, false, true - } else { - return m.Type, true, true - } - } - - d := t - if t.Kind() == reflect.Ptr { - d = t.Elem() - } - - switch d.Kind() { - case reflect.Interface: - return interfaceType, false, true - case reflect.Struct: - // First, check all struct's fields. - for i := 0; i < d.NumField(); i++ { - f := d.Field(i) - if !f.Anonymous && f.Name == name { - return f.Type, false, true - } - } - - // Second, check fields of embedded structs. - for i := 0; i < d.NumField(); i++ { - f := d.Field(i) - if f.Anonymous { - if t, method, ok := methodType(f.Type, name); ok { - return t, method, true - } - } - } - - case reflect.Map: - return d.Elem(), false, true - } - } - return nil, false, false -} - -func indexType(ntype reflect.Type) (reflect.Type, bool) { - ntype = dereference(ntype) - if ntype == nil { - return nil, false - } - - switch ntype.Kind() { - case reflect.Interface: - return interfaceType, true - case reflect.Map, reflect.Array, reflect.Slice: - return ntype.Elem(), true - } - - return nil, false -} - -func isFuncType(ntype reflect.Type) (reflect.Type, bool) { - ntype = dereference(ntype) - if ntype == nil { - return nil, false - } - - switch ntype.Kind() { - case reflect.Interface: - return interfaceType, true - case reflect.Func: - return ntype, true - } - - return nil, false -} - -func isIntegerOrArithmeticOperation(node ast.Node) bool { - switch n := node.(type) { - case *ast.IntegerNode: - return true - case *ast.UnaryNode: - switch n.Operator { - case "+", "-": - return true - } - case *ast.BinaryNode: - switch n.Operator { - case "+", "/", "-", "*": - return true - } - } - return false -} - -func setTypeForIntegers(node ast.Node, t reflect.Type) { - switch n := node.(type) { - case *ast.IntegerNode: - n.SetType(t) - case *ast.UnaryNode: - switch n.Operator { - case "+", "-": - setTypeForIntegers(n.Node, t) - } - case *ast.BinaryNode: - switch n.Operator { - case "+", "/", "-", "*": - setTypeForIntegers(n.Left, t) - setTypeForIntegers(n.Right, t) - } - } -} diff --git a/vendor/github.com/antonmedv/expr/compiler/compiler.go b/vendor/github.com/antonmedv/expr/compiler/compiler.go deleted file mode 100644 index 36ac92f..0000000 --- a/vendor/github.com/antonmedv/expr/compiler/compiler.go +++ /dev/null @@ -1,673 +0,0 @@ -package compiler - -import ( - "encoding/binary" - "fmt" - "math" - "reflect" - - "github.com/antonmedv/expr/ast" - "github.com/antonmedv/expr/conf" - "github.com/antonmedv/expr/file" - "github.com/antonmedv/expr/parser" - . "github.com/antonmedv/expr/vm" -) - -func Compile(tree *parser.Tree, config *conf.Config) (program *Program, err error) { - defer func() { - if r := recover(); r != nil { - err = fmt.Errorf("%v", r) - } - }() - - c := &compiler{ - index: make(map[interface{}]uint16), - locations: make(map[int]file.Location), - } - - if config != nil { - c.mapEnv = config.MapEnv - c.cast = config.Expect - } - - c.compile(tree.Node) - - switch c.cast { - case reflect.Int64: - c.emit(OpCast, encode(0)...) - case reflect.Float64: - c.emit(OpCast, encode(1)...) - } - - program = &Program{ - Source: tree.Source, - Locations: c.locations, - Constants: c.constants, - Bytecode: c.bytecode, - } - return -} - -type compiler struct { - locations map[int]file.Location - constants []interface{} - bytecode []byte - index map[interface{}]uint16 - mapEnv bool - cast reflect.Kind - nodes []ast.Node -} - -func (c *compiler) emit(op byte, b ...byte) int { - c.bytecode = append(c.bytecode, op) - current := len(c.bytecode) - c.bytecode = append(c.bytecode, b...) - - var loc file.Location - if len(c.nodes) > 0 { - loc = c.nodes[len(c.nodes)-1].Location() - } - c.locations[current-1] = loc - - return current -} - -func (c *compiler) emitPush(value interface{}) int { - return c.emit(OpPush, c.makeConstant(value)...) -} - -func (c *compiler) makeConstant(i interface{}) []byte { - hashable := true - switch reflect.TypeOf(i).Kind() { - case reflect.Slice, reflect.Map: - hashable = false - } - - if hashable { - if p, ok := c.index[i]; ok { - return encode(p) - } - } - - c.constants = append(c.constants, i) - if len(c.constants) > math.MaxUint16 { - panic("exceeded constants max space limit") - } - - p := uint16(len(c.constants) - 1) - if hashable { - c.index[i] = p - } - return encode(p) -} - -func (c *compiler) placeholder() []byte { - return []byte{0xFF, 0xFF} -} - -func (c *compiler) patchJump(placeholder int) { - offset := len(c.bytecode) - 2 - placeholder - b := encode(uint16(offset)) - c.bytecode[placeholder] = b[0] - c.bytecode[placeholder+1] = b[1] -} - -func (c *compiler) calcBackwardJump(to int) []byte { - return encode(uint16(len(c.bytecode) + 1 + 2 - to)) -} - -func (c *compiler) compile(node ast.Node) { - c.nodes = append(c.nodes, node) - defer func() { - c.nodes = c.nodes[:len(c.nodes)-1] - }() - - switch n := node.(type) { - case *ast.NilNode: - c.NilNode(n) - case *ast.IdentifierNode: - c.IdentifierNode(n) - case *ast.IntegerNode: - c.IntegerNode(n) - case *ast.FloatNode: - c.FloatNode(n) - case *ast.BoolNode: - c.BoolNode(n) - case *ast.StringNode: - c.StringNode(n) - case *ast.ConstantNode: - c.ConstantNode(n) - case *ast.UnaryNode: - c.UnaryNode(n) - case *ast.BinaryNode: - c.BinaryNode(n) - case *ast.MatchesNode: - c.MatchesNode(n) - case *ast.PropertyNode: - c.PropertyNode(n) - case *ast.IndexNode: - c.IndexNode(n) - case *ast.SliceNode: - c.SliceNode(n) - case *ast.MethodNode: - c.MethodNode(n) - case *ast.FunctionNode: - c.FunctionNode(n) - case *ast.BuiltinNode: - c.BuiltinNode(n) - case *ast.ClosureNode: - c.ClosureNode(n) - case *ast.PointerNode: - c.PointerNode(n) - case *ast.ConditionalNode: - c.ConditionalNode(n) - case *ast.ArrayNode: - c.ArrayNode(n) - case *ast.MapNode: - c.MapNode(n) - case *ast.PairNode: - c.PairNode(n) - default: - panic(fmt.Sprintf("undefined node type (%T)", node)) - } -} - -func (c *compiler) NilNode(node *ast.NilNode) { - c.emit(OpNil) -} - -func (c *compiler) IdentifierNode(node *ast.IdentifierNode) { - v := c.makeConstant(node.Value) - if c.mapEnv { - c.emit(OpFetchMap, v...) - } else if node.NilSafe { - c.emit(OpFetchNilSafe, v...) - } else { - c.emit(OpFetch, v...) - } -} - -func (c *compiler) IntegerNode(node *ast.IntegerNode) { - t := node.Type() - if t == nil { - c.emitPush(node.Value) - return - } - - switch t.Kind() { - case reflect.Float32: - c.emitPush(float32(node.Value)) - case reflect.Float64: - c.emitPush(float64(node.Value)) - - case reflect.Int: - c.emitPush(int(node.Value)) - case reflect.Int8: - c.emitPush(int8(node.Value)) - case reflect.Int16: - c.emitPush(int16(node.Value)) - case reflect.Int32: - c.emitPush(int32(node.Value)) - case reflect.Int64: - c.emitPush(int64(node.Value)) - - case reflect.Uint: - c.emitPush(uint(node.Value)) - case reflect.Uint8: - c.emitPush(uint8(node.Value)) - case reflect.Uint16: - c.emitPush(uint16(node.Value)) - case reflect.Uint32: - c.emitPush(uint32(node.Value)) - case reflect.Uint64: - c.emitPush(uint64(node.Value)) - - default: - c.emitPush(node.Value) - } -} - -func (c *compiler) FloatNode(node *ast.FloatNode) { - c.emitPush(node.Value) -} - -func (c *compiler) BoolNode(node *ast.BoolNode) { - if node.Value { - c.emit(OpTrue) - } else { - c.emit(OpFalse) - } -} - -func (c *compiler) StringNode(node *ast.StringNode) { - c.emitPush(node.Value) -} - -func (c *compiler) ConstantNode(node *ast.ConstantNode) { - c.emitPush(node.Value) -} - -func (c *compiler) UnaryNode(node *ast.UnaryNode) { - c.compile(node.Node) - - switch node.Operator { - - case "!", "not": - c.emit(OpNot) - - case "+": - // Do nothing - - case "-": - c.emit(OpNegate) - - default: - panic(fmt.Sprintf("unknown operator (%v)", node.Operator)) - } -} - -func (c *compiler) BinaryNode(node *ast.BinaryNode) { - l := kind(node.Left) - r := kind(node.Right) - - switch node.Operator { - case "==": - c.compile(node.Left) - c.compile(node.Right) - - if l == r && l == reflect.Int { - c.emit(OpEqualInt) - } else if l == r && l == reflect.String { - c.emit(OpEqualString) - } else { - c.emit(OpEqual) - } - - case "!=": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpEqual) - c.emit(OpNot) - - case "or", "||": - c.compile(node.Left) - end := c.emit(OpJumpIfTrue, c.placeholder()...) - c.emit(OpPop) - c.compile(node.Right) - c.patchJump(end) - - case "and", "&&": - c.compile(node.Left) - end := c.emit(OpJumpIfFalse, c.placeholder()...) - c.emit(OpPop) - c.compile(node.Right) - c.patchJump(end) - - case "in": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpIn) - - case "not in": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpIn) - c.emit(OpNot) - - case "<": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpLess) - - case ">": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpMore) - - case "<=": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpLessOrEqual) - - case ">=": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpMoreOrEqual) - - case "+": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpAdd) - - case "-": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpSubtract) - - case "*": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpMultiply) - - case "/": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpDivide) - - case "%": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpModulo) - - case "**": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpExponent) - - case "contains": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpContains) - - case "startsWith": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpStartsWith) - - case "endsWith": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpEndsWith) - - case "..": - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpRange) - - default: - panic(fmt.Sprintf("unknown operator (%v)", node.Operator)) - - } -} - -func (c *compiler) MatchesNode(node *ast.MatchesNode) { - if node.Regexp != nil { - c.compile(node.Left) - c.emit(OpMatchesConst, c.makeConstant(node.Regexp)...) - return - } - c.compile(node.Left) - c.compile(node.Right) - c.emit(OpMatches) -} - -func (c *compiler) PropertyNode(node *ast.PropertyNode) { - c.compile(node.Node) - if !node.NilSafe { - c.emit(OpProperty, c.makeConstant(node.Property)...) - } else { - c.emit(OpPropertyNilSafe, c.makeConstant(node.Property)...) - } -} - -func (c *compiler) IndexNode(node *ast.IndexNode) { - c.compile(node.Node) - c.compile(node.Index) - c.emit(OpIndex) -} - -func (c *compiler) SliceNode(node *ast.SliceNode) { - c.compile(node.Node) - if node.To != nil { - c.compile(node.To) - } else { - c.emit(OpLen) - } - if node.From != nil { - c.compile(node.From) - } else { - c.emitPush(0) - } - c.emit(OpSlice) -} - -func (c *compiler) MethodNode(node *ast.MethodNode) { - c.compile(node.Node) - for _, arg := range node.Arguments { - c.compile(arg) - } - if !node.NilSafe { - c.emit(OpMethod, c.makeConstant(Call{Name: node.Method, Size: len(node.Arguments)})...) - } else { - c.emit(OpMethodNilSafe, c.makeConstant(Call{Name: node.Method, Size: len(node.Arguments)})...) - } -} - -func (c *compiler) FunctionNode(node *ast.FunctionNode) { - for _, arg := range node.Arguments { - c.compile(arg) - } - op := OpCall - if node.Fast { - op = OpCallFast - } - c.emit(op, c.makeConstant(Call{Name: node.Name, Size: len(node.Arguments)})...) -} - -func (c *compiler) BuiltinNode(node *ast.BuiltinNode) { - switch node.Name { - case "len": - c.compile(node.Arguments[0]) - c.emit(OpLen) - c.emit(OpRot) - c.emit(OpPop) - - case "all": - c.compile(node.Arguments[0]) - c.emit(OpBegin) - var loopBreak int - c.emitLoop(func() { - c.compile(node.Arguments[1]) - loopBreak = c.emit(OpJumpIfFalse, c.placeholder()...) - c.emit(OpPop) - }) - c.emit(OpTrue) - c.patchJump(loopBreak) - c.emit(OpEnd) - - case "none": - c.compile(node.Arguments[0]) - c.emit(OpBegin) - var loopBreak int - c.emitLoop(func() { - c.compile(node.Arguments[1]) - c.emit(OpNot) - loopBreak = c.emit(OpJumpIfFalse, c.placeholder()...) - c.emit(OpPop) - }) - c.emit(OpTrue) - c.patchJump(loopBreak) - c.emit(OpEnd) - - case "any": - c.compile(node.Arguments[0]) - c.emit(OpBegin) - var loopBreak int - c.emitLoop(func() { - c.compile(node.Arguments[1]) - loopBreak = c.emit(OpJumpIfTrue, c.placeholder()...) - c.emit(OpPop) - }) - c.emit(OpFalse) - c.patchJump(loopBreak) - c.emit(OpEnd) - - case "one": - count := c.makeConstant("count") - c.compile(node.Arguments[0]) - c.emit(OpBegin) - c.emitPush(0) - c.emit(OpStore, count...) - c.emitLoop(func() { - c.compile(node.Arguments[1]) - c.emitCond(func() { - c.emit(OpInc, count...) - }) - }) - c.emit(OpLoad, count...) - c.emitPush(1) - c.emit(OpEqual) - c.emit(OpEnd) - - case "filter": - count := c.makeConstant("count") - c.compile(node.Arguments[0]) - c.emit(OpBegin) - c.emitPush(0) - c.emit(OpStore, count...) - c.emitLoop(func() { - c.compile(node.Arguments[1]) - c.emitCond(func() { - c.emit(OpInc, count...) - - c.emit(OpLoad, c.makeConstant("array")...) - c.emit(OpLoad, c.makeConstant("i")...) - c.emit(OpIndex) - }) - }) - c.emit(OpLoad, count...) - c.emit(OpEnd) - c.emit(OpArray) - - case "map": - c.compile(node.Arguments[0]) - c.emit(OpBegin) - size := c.emitLoop(func() { - c.compile(node.Arguments[1]) - }) - c.emit(OpLoad, size...) - c.emit(OpEnd) - c.emit(OpArray) - - case "count": - count := c.makeConstant("count") - c.compile(node.Arguments[0]) - c.emit(OpBegin) - c.emitPush(0) - c.emit(OpStore, count...) - c.emitLoop(func() { - c.compile(node.Arguments[1]) - c.emitCond(func() { - c.emit(OpInc, count...) - }) - }) - c.emit(OpLoad, count...) - c.emit(OpEnd) - - default: - panic(fmt.Sprintf("unknown builtin %v", node.Name)) - } -} - -func (c *compiler) emitCond(body func()) { - noop := c.emit(OpJumpIfFalse, c.placeholder()...) - c.emit(OpPop) - - body() - - jmp := c.emit(OpJump, c.placeholder()...) - c.patchJump(noop) - c.emit(OpPop) - c.patchJump(jmp) -} - -func (c *compiler) emitLoop(body func()) []byte { - i := c.makeConstant("i") - size := c.makeConstant("size") - array := c.makeConstant("array") - - c.emit(OpLen) - c.emit(OpStore, size...) - c.emit(OpStore, array...) - c.emitPush(0) - c.emit(OpStore, i...) - - cond := len(c.bytecode) - c.emit(OpLoad, i...) - c.emit(OpLoad, size...) - c.emit(OpLess) - end := c.emit(OpJumpIfFalse, c.placeholder()...) - c.emit(OpPop) - - body() - - c.emit(OpInc, i...) - c.emit(OpJumpBackward, c.calcBackwardJump(cond)...) - - c.patchJump(end) - c.emit(OpPop) - - return size -} - -func (c *compiler) ClosureNode(node *ast.ClosureNode) { - c.compile(node.Node) -} - -func (c *compiler) PointerNode(node *ast.PointerNode) { - c.emit(OpLoad, c.makeConstant("array")...) - c.emit(OpLoad, c.makeConstant("i")...) - c.emit(OpIndex) -} - -func (c *compiler) ConditionalNode(node *ast.ConditionalNode) { - c.compile(node.Cond) - otherwise := c.emit(OpJumpIfFalse, c.placeholder()...) - - c.emit(OpPop) - c.compile(node.Exp1) - end := c.emit(OpJump, c.placeholder()...) - - c.patchJump(otherwise) - c.emit(OpPop) - c.compile(node.Exp2) - - c.patchJump(end) -} - -func (c *compiler) ArrayNode(node *ast.ArrayNode) { - for _, node := range node.Nodes { - c.compile(node) - } - - c.emitPush(len(node.Nodes)) - c.emit(OpArray) -} - -func (c *compiler) MapNode(node *ast.MapNode) { - for _, pair := range node.Pairs { - c.compile(pair) - } - - c.emitPush(len(node.Pairs)) - c.emit(OpMap) -} - -func (c *compiler) PairNode(node *ast.PairNode) { - c.compile(node.Key) - c.compile(node.Value) -} - -func encode(i uint16) []byte { - b := make([]byte, 2) - binary.LittleEndian.PutUint16(b, i) - return b -} - -func kind(node ast.Node) reflect.Kind { - t := node.Type() - if t == nil { - return reflect.Invalid - } - return t.Kind() -} diff --git a/vendor/github.com/antonmedv/expr/compiler/patcher.go b/vendor/github.com/antonmedv/expr/compiler/patcher.go deleted file mode 100644 index 2491dec..0000000 --- a/vendor/github.com/antonmedv/expr/compiler/patcher.go +++ /dev/null @@ -1,44 +0,0 @@ -package compiler - -import ( - "github.com/antonmedv/expr/ast" - "github.com/antonmedv/expr/conf" -) - -type operatorPatcher struct { - ops map[string][]string - types conf.TypesTable -} - -func (p *operatorPatcher) Enter(node *ast.Node) {} -func (p *operatorPatcher) Exit(node *ast.Node) { - binaryNode, ok := (*node).(*ast.BinaryNode) - if !ok { - return - } - - fns, ok := p.ops[binaryNode.Operator] - if !ok { - return - } - - leftType := binaryNode.Left.Type() - rightType := binaryNode.Right.Type() - - _, fn, ok := conf.FindSuitableOperatorOverload(fns, p.types, leftType, rightType) - if ok { - newNode := &ast.FunctionNode{ - Name: fn, - Arguments: []ast.Node{binaryNode.Left, binaryNode.Right}, - } - ast.Patch(node, newNode) - } -} - -func PatchOperators(node *ast.Node, config *conf.Config) { - if len(config.Operators) == 0 { - return - } - patcher := &operatorPatcher{ops: config.Operators, types: config.Types} - ast.Walk(node, patcher) -} diff --git a/vendor/github.com/antonmedv/expr/conf/config.go b/vendor/github.com/antonmedv/expr/conf/config.go deleted file mode 100644 index 7ba07fe..0000000 --- a/vendor/github.com/antonmedv/expr/conf/config.go +++ /dev/null @@ -1,89 +0,0 @@ -package conf - -import ( - "fmt" - "reflect" - - "github.com/antonmedv/expr/ast" - "github.com/antonmedv/expr/vm" -) - -type Config struct { - Env interface{} - MapEnv bool - Types TypesTable - Operators OperatorsTable - Expect reflect.Kind - Optimize bool - Strict bool - DefaultType reflect.Type - ConstExprFns map[string]reflect.Value - Visitors []ast.Visitor - err error -} - -func New(env interface{}) *Config { - var mapEnv bool - var mapValueType reflect.Type - if _, ok := env.(map[string]interface{}); ok { - mapEnv = true - } else { - if reflect.ValueOf(env).Kind() == reflect.Map { - mapValueType = reflect.TypeOf(env).Elem() - } - } - - return &Config{ - Env: env, - MapEnv: mapEnv, - Types: CreateTypesTable(env), - Optimize: true, - Strict: true, - DefaultType: mapValueType, - ConstExprFns: make(map[string]reflect.Value), - } -} - -// Check validates the compiler configuration. -func (c *Config) Check() error { - // Check that all functions that define operator overloading - // exist in environment and have correct signatures. - for op, fns := range c.Operators { - for _, fn := range fns { - fnType, ok := c.Types[fn] - if !ok || fnType.Type.Kind() != reflect.Func { - return fmt.Errorf("function %s for %s operator does not exist in environment", fn, op) - } - requiredNumIn := 2 - if fnType.Method { - requiredNumIn = 3 // As first argument of method is receiver. - } - if fnType.Type.NumIn() != requiredNumIn || fnType.Type.NumOut() != 1 { - return fmt.Errorf("function %s for %s operator does not have a correct signature", fn, op) - } - } - } - - // Check that all ConstExprFns are functions. - for name, fn := range c.ConstExprFns { - if fn.Kind() != reflect.Func { - return fmt.Errorf("const expression %q must be a function", name) - } - } - - return c.err -} - -func (c *Config) ConstExpr(name string) { - if c.Env == nil { - c.Error(fmt.Errorf("no environment for const expression: %v", name)) - return - } - c.ConstExprFns[name] = vm.FetchFn(c.Env, name) -} - -func (c *Config) Error(err error) { - if c.err == nil { - c.err = err - } -} diff --git a/vendor/github.com/antonmedv/expr/conf/operators_table.go b/vendor/github.com/antonmedv/expr/conf/operators_table.go deleted file mode 100644 index 0ceb844..0000000 --- a/vendor/github.com/antonmedv/expr/conf/operators_table.go +++ /dev/null @@ -1,26 +0,0 @@ -package conf - -import "reflect" - -// OperatorsTable maps binary operators to corresponding list of functions. -// Functions should be provided in the environment to allow operator overloading. -type OperatorsTable map[string][]string - -func FindSuitableOperatorOverload(fns []string, types TypesTable, l, r reflect.Type) (reflect.Type, string, bool) { - for _, fn := range fns { - fnType := types[fn] - firstInIndex := 0 - if fnType.Method { - firstInIndex = 1 // As first argument to method is receiver. - } - firstArgType := fnType.Type.In(firstInIndex) - secondArgType := fnType.Type.In(firstInIndex + 1) - - firstArgumentFit := l == firstArgType || (firstArgType.Kind() == reflect.Interface && (l == nil || l.Implements(firstArgType))) - secondArgumentFit := r == secondArgType || (secondArgType.Kind() == reflect.Interface && (r == nil || r.Implements(secondArgType))) - if firstArgumentFit && secondArgumentFit { - return fnType.Type.Out(0), fn, true - } - } - return nil, "", false -} diff --git a/vendor/github.com/antonmedv/expr/conf/types_table.go b/vendor/github.com/antonmedv/expr/conf/types_table.go deleted file mode 100644 index d5539da..0000000 --- a/vendor/github.com/antonmedv/expr/conf/types_table.go +++ /dev/null @@ -1,100 +0,0 @@ -package conf - -import "reflect" - -type Tag struct { - Type reflect.Type - Method bool - Ambiguous bool -} - -type TypesTable map[string]Tag - -// CreateTypesTable creates types table for type checks during parsing. -// If struct is passed, all fields will be treated as variables, -// as well as all fields of embedded structs and struct itself. -// -// If map is passed, all items will be treated as variables -// (key as name, value as type). -func CreateTypesTable(i interface{}) TypesTable { - if i == nil { - return nil - } - - types := make(TypesTable) - v := reflect.ValueOf(i) - t := reflect.TypeOf(i) - - d := t - if t.Kind() == reflect.Ptr { - d = t.Elem() - } - - switch d.Kind() { - case reflect.Struct: - types = FieldsFromStruct(d) - - // Methods of struct should be gathered from original struct with pointer, - // as methods maybe declared on pointer receiver. Also this method retrieves - // all embedded structs methods as well, no need to recursion. - for i := 0; i < t.NumMethod(); i++ { - m := t.Method(i) - types[m.Name] = Tag{Type: m.Type, Method: true} - } - - case reflect.Map: - for _, key := range v.MapKeys() { - value := v.MapIndex(key) - if key.Kind() == reflect.String && value.IsValid() && value.CanInterface() { - types[key.String()] = Tag{Type: reflect.TypeOf(value.Interface())} - } - } - - // A map may have method too. - for i := 0; i < t.NumMethod(); i++ { - m := t.Method(i) - types[m.Name] = Tag{Type: m.Type, Method: true} - } - } - - return types -} - -func FieldsFromStruct(t reflect.Type) TypesTable { - types := make(TypesTable) - t = dereference(t) - if t == nil { - return types - } - - switch t.Kind() { - case reflect.Struct: - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - - if f.Anonymous { - for name, typ := range FieldsFromStruct(f.Type) { - if _, ok := types[name]; ok { - types[name] = Tag{Ambiguous: true} - } else { - types[name] = typ - } - } - } - - types[f.Name] = Tag{Type: f.Type} - } - } - - return types -} - -func dereference(t reflect.Type) reflect.Type { - if t == nil { - return nil - } - if t.Kind() == reflect.Ptr { - t = dereference(t.Elem()) - } - return t -} diff --git a/vendor/github.com/antonmedv/expr/expr.go b/vendor/github.com/antonmedv/expr/expr.go deleted file mode 100644 index 05c54ad..0000000 --- a/vendor/github.com/antonmedv/expr/expr.go +++ /dev/null @@ -1,187 +0,0 @@ -package expr - -import ( - "fmt" - "github.com/antonmedv/expr/ast" - "github.com/antonmedv/expr/file" - "reflect" - - "github.com/antonmedv/expr/checker" - "github.com/antonmedv/expr/compiler" - "github.com/antonmedv/expr/conf" - "github.com/antonmedv/expr/optimizer" - "github.com/antonmedv/expr/parser" - "github.com/antonmedv/expr/vm" -) - -// Option for configuring config. -type Option func(c *conf.Config) - -// Eval parses, compiles and runs given input. -func Eval(input string, env interface{}) (interface{}, error) { - if _, ok := env.(Option); ok { - return nil, fmt.Errorf("misused expr.Eval: second argument (env) should be passed without expr.Env") - } - - tree, err := parser.Parse(input) - if err != nil { - return nil, err - } - - program, err := compiler.Compile(tree, nil) - if err != nil { - return nil, err - } - - output, err := vm.Run(program, env) - if err != nil { - return nil, err - } - - return output, nil -} - -// Env specifies expected input of env for type checks. -// If struct is passed, all fields will be treated as variables, -// as well as all fields of embedded structs and struct itself. -// If map is passed, all items will be treated as variables. -// Methods defined on this type will be available as functions. -func Env(env interface{}) Option { - return func(c *conf.Config) { - if _, ok := env.(map[string]interface{}); ok { - c.MapEnv = true - } else { - if reflect.ValueOf(env).Kind() == reflect.Map { - c.DefaultType = reflect.TypeOf(env).Elem() - } - } - c.Strict = true - c.Types = conf.CreateTypesTable(env) - c.Env = env - } -} - -// AllowUndefinedVariables allows to use undefined variables inside expressions. -// This can be used with expr.Env option to partially define a few variables. -// Note what this option is only works in map environment are used, otherwise -// runtime.fetch will panic as there is no way to get missing field zero value. -func AllowUndefinedVariables() Option { - return func(c *conf.Config) { - c.Strict = false - } -} - -// Operator allows to override binary operator with function. -func Operator(operator string, fn ...string) Option { - return func(c *conf.Config) { - c.Operators[operator] = append(c.Operators[operator], fn...) - } -} - -// ConstExpr defines func expression as constant. If all argument to this function is constants, -// then it can be replaced by result of this func call on compile step. -func ConstExpr(fn string) Option { - return func(c *conf.Config) { - c.ConstExpr(fn) - } -} - -// AsBool tells the compiler to expect boolean result. -func AsBool() Option { - return func(c *conf.Config) { - c.Expect = reflect.Bool - } -} - -// AsInt64 tells the compiler to expect int64 result. -func AsInt64() Option { - return func(c *conf.Config) { - c.Expect = reflect.Int64 - } -} - -// AsFloat64 tells the compiler to expect float64 result. -func AsFloat64() Option { - return func(c *conf.Config) { - c.Expect = reflect.Float64 - } -} - -// Optimize turns optimizations on or off. -func Optimize(b bool) Option { - return func(c *conf.Config) { - c.Optimize = b - } -} - -// Patch adds visitor to list of visitors what will be applied before compiling AST to bytecode. -func Patch(visitor ast.Visitor) Option { - return func(c *conf.Config) { - c.Visitors = append(c.Visitors, visitor) - } -} - -// Compile parses and compiles given input expression to bytecode program. -func Compile(input string, ops ...Option) (*vm.Program, error) { - config := &conf.Config{ - Operators: make(map[string][]string), - ConstExprFns: make(map[string]reflect.Value), - Optimize: true, - } - - for _, op := range ops { - op(config) - } - - if err := config.Check(); err != nil { - return nil, err - } - - tree, err := parser.Parse(input) - if err != nil { - return nil, err - } - - _, err = checker.Check(tree, config) - - // If we have a patch to apply, it may fix out error and - // second type check is needed. Otherwise it is an error. - if err != nil && len(config.Visitors) == 0 { - return nil, err - } - - // Patch operators before Optimize, as we may also mark it as ConstExpr. - compiler.PatchOperators(&tree.Node, config) - - if len(config.Visitors) >= 0 { - for _, v := range config.Visitors { - ast.Walk(&tree.Node, v) - } - _, err = checker.Check(tree, config) - if err != nil { - return nil, err - } - } - - if config.Optimize { - err = optimizer.Optimize(&tree.Node, config) - if err != nil { - if fileError, ok := err.(*file.Error); ok { - return nil, fileError.Bind(tree.Source) - } - return nil, err - } - } - - program, err := compiler.Compile(tree, config) - if err != nil { - return nil, err - } - - return program, nil -} - -// Run evaluates given bytecode program. -func Run(program *vm.Program, env interface{}) (interface{}, error) { - return vm.Run(program, env) -} diff --git a/vendor/github.com/antonmedv/expr/file/error.go b/vendor/github.com/antonmedv/expr/file/error.go deleted file mode 100644 index b7af3e6..0000000 --- a/vendor/github.com/antonmedv/expr/file/error.go +++ /dev/null @@ -1,58 +0,0 @@ -package file - -import ( - "fmt" - "strings" - "unicode/utf8" -) - -type Error struct { - Location - Message string - Snippet string -} - -func (e *Error) Error() string { - return e.format() -} - -func (e *Error) Bind(source *Source) *Error { - if snippet, found := source.Snippet(e.Location.Line); found { - snippet := strings.Replace(snippet, "\t", " ", -1) - srcLine := "\n | " + snippet - var bytes = []byte(snippet) - var indLine = "\n | " - for i := 0; i < e.Location.Column && len(bytes) > 0; i++ { - _, sz := utf8.DecodeRune(bytes) - bytes = bytes[sz:] - if sz > 1 { - goto noind - } else { - indLine += "." - } - } - if _, sz := utf8.DecodeRune(bytes); sz > 1 { - goto noind - } else { - indLine += "^" - } - srcLine += indLine - - noind: - e.Snippet = srcLine - } - return e -} - -func (e *Error) format() string { - if e.Location.Empty() { - return e.Message - } - return fmt.Sprintf( - "%s (%d:%d)%s", - e.Message, - e.Line, - e.Column+1, // add one to the 0-based column for display - e.Snippet, - ) -} diff --git a/vendor/github.com/antonmedv/expr/file/location.go b/vendor/github.com/antonmedv/expr/file/location.go deleted file mode 100644 index a92e27f..0000000 --- a/vendor/github.com/antonmedv/expr/file/location.go +++ /dev/null @@ -1,10 +0,0 @@ -package file - -type Location struct { - Line int // The 1-based line of the location. - Column int // The 0-based column number of the location. -} - -func (l Location) Empty() bool { - return l.Column == 0 && l.Line == 0 -} diff --git a/vendor/github.com/antonmedv/expr/file/source.go b/vendor/github.com/antonmedv/expr/file/source.go deleted file mode 100644 index 185d156..0000000 --- a/vendor/github.com/antonmedv/expr/file/source.go +++ /dev/null @@ -1,95 +0,0 @@ -package file - -import ( - "encoding/json" - "strings" - "unicode/utf8" -) - -type Source struct { - contents []rune - lineOffsets []int32 -} - -func NewSource(contents string) *Source { - s := &Source{ - contents: []rune(contents), - } - s.updateOffsets() - return s -} - -func (s *Source) MarshalJSON() ([]byte, error) { - return json.Marshal(s.contents) -} - -func (s *Source) UnmarshalJSON(b []byte) error { - contents := make([]rune, 0) - err := json.Unmarshal(b, &contents) - if err != nil { - return err - } - - s.contents = contents - s.updateOffsets() - return nil -} - -func (s *Source) Content() string { - return string(s.contents) -} - -func (s *Source) Snippet(line int) (string, bool) { - charStart, found := s.findLineOffset(line) - if !found || len(s.contents) == 0 { - return "", false - } - charEnd, found := s.findLineOffset(line + 1) - if found { - return string(s.contents[charStart : charEnd-1]), true - } - return string(s.contents[charStart:]), true -} - -// updateOffsets compute line offsets up front as they are referred to frequently. -func (s *Source) updateOffsets() { - lines := strings.Split(string(s.contents), "\n") - offsets := make([]int32, len(lines)) - var offset int32 - for i, line := range lines { - offset = offset + int32(utf8.RuneCountInString(line)) + 1 - offsets[int32(i)] = offset - } - s.lineOffsets = offsets -} - -// findLineOffset returns the offset where the (1-indexed) line begins, -// or false if line doesn't exist. -func (s *Source) findLineOffset(line int) (int32, bool) { - if line == 1 { - return 0, true - } else if line > 1 && line <= len(s.lineOffsets) { - offset := s.lineOffsets[line-2] - return offset, true - } - return -1, false -} - -// findLine finds the line that contains the given character offset and -// returns the line number and offset of the beginning of that line. -// Note that the last line is treated as if it contains all offsets -// beyond the end of the actual source. -func (s *Source) findLine(characterOffset int32) (int32, int32) { - var line int32 = 1 - for _, lineOffset := range s.lineOffsets { - if lineOffset > characterOffset { - break - } else { - line++ - } - } - if line == 1 { - return line, 0 - } - return line, s.lineOffsets[line-2] -} diff --git a/vendor/github.com/antonmedv/expr/optimizer/const_expr.go b/vendor/github.com/antonmedv/expr/optimizer/const_expr.go deleted file mode 100644 index 85fcc33..0000000 --- a/vendor/github.com/antonmedv/expr/optimizer/const_expr.go +++ /dev/null @@ -1,77 +0,0 @@ -package optimizer - -import ( - "fmt" - . "github.com/antonmedv/expr/ast" - "github.com/antonmedv/expr/file" - "reflect" - "strings" -) - -type constExpr struct { - applied bool - err error - fns map[string]reflect.Value -} - -func (*constExpr) Enter(*Node) {} -func (c *constExpr) Exit(node *Node) { - defer func() { - if r := recover(); r != nil { - msg := fmt.Sprintf("%v", r) - // Make message more actual, it's a runtime error, but at compile step. - msg = strings.Replace(msg, "runtime error:", "compile error:", 1) - c.err = &file.Error{ - Location: (*node).Location(), - Message: msg, - } - } - }() - - patch := func(newNode Node) { - c.applied = true - Patch(node, newNode) - } - - switch n := (*node).(type) { - case *FunctionNode: - fn, ok := c.fns[n.Name] - if ok { - in := make([]reflect.Value, len(n.Arguments)) - for i := 0; i < len(n.Arguments); i++ { - arg := n.Arguments[i] - var param interface{} - - switch a := arg.(type) { - case *NilNode: - param = nil - case *IntegerNode: - param = a.Value - case *FloatNode: - param = a.Value - case *BoolNode: - param = a.Value - case *StringNode: - param = a.Value - case *ConstantNode: - param = a.Value - - default: - return // Const expr optimization not applicable. - } - - if param == nil && reflect.TypeOf(param) == nil { - // In case of nil value and nil type use this hack, - // otherwise reflect.Call will panic on zero value. - in[i] = reflect.ValueOf(¶m).Elem() - } else { - in[i] = reflect.ValueOf(param) - } - } - - out := fn.Call(in) - constNode := &ConstantNode{Value: out[0].Interface()} - patch(constNode) - } - } -} diff --git a/vendor/github.com/antonmedv/expr/optimizer/const_range.go b/vendor/github.com/antonmedv/expr/optimizer/const_range.go deleted file mode 100644 index 5205aa1..0000000 --- a/vendor/github.com/antonmedv/expr/optimizer/const_range.go +++ /dev/null @@ -1,41 +0,0 @@ -package optimizer - -import ( - . "github.com/antonmedv/expr/ast" -) - -type constRange struct{} - -func (*constRange) Enter(*Node) {} -func (*constRange) Exit(node *Node) { - switch n := (*node).(type) { - case *BinaryNode: - if n.Operator == ".." { - if min, ok := n.Left.(*IntegerNode); ok { - if max, ok := n.Right.(*IntegerNode); ok { - size := max.Value - min.Value + 1 - // In case the max < min, patch empty slice - // as max must be greater than equal to min. - if size < 1 { - Patch(node, &ConstantNode{ - Value: make([]int, 0), - }) - return - } - // In this case array is too big. Skip generation, - // and wait for memory budget detection on runtime. - if size > 1e6 { - return - } - value := make([]int, size) - for i := range value { - value[i] = min.Value + i - } - Patch(node, &ConstantNode{ - Value: value, - }) - } - } - } - } -} diff --git a/vendor/github.com/antonmedv/expr/optimizer/fold.go b/vendor/github.com/antonmedv/expr/optimizer/fold.go deleted file mode 100644 index 6669125..0000000 --- a/vendor/github.com/antonmedv/expr/optimizer/fold.go +++ /dev/null @@ -1,133 +0,0 @@ -package optimizer - -import ( - "math" - "reflect" - - . "github.com/antonmedv/expr/ast" - "github.com/antonmedv/expr/file" -) - -type fold struct { - applied bool - err *file.Error -} - -func (*fold) Enter(*Node) {} -func (fold *fold) Exit(node *Node) { - patch := func(newNode Node) { - fold.applied = true - Patch(node, newNode) - } - // for IntegerNode the type may have been changed from int->float - // preserve this information by setting the type after the Patch - patchWithType := func(newNode Node, leafType reflect.Type) { - patch(newNode) - newNode.SetType(leafType) - } - - switch n := (*node).(type) { - case *UnaryNode: - switch n.Operator { - case "-": - if i, ok := n.Node.(*IntegerNode); ok { - patchWithType(&IntegerNode{Value: -i.Value}, n.Node.Type()) - } - case "+": - if i, ok := n.Node.(*IntegerNode); ok { - patchWithType(&IntegerNode{Value: i.Value}, n.Node.Type()) - } - } - - case *BinaryNode: - switch n.Operator { - case "+": - if a, ok := n.Left.(*IntegerNode); ok { - if b, ok := n.Right.(*IntegerNode); ok { - patchWithType(&IntegerNode{Value: a.Value + b.Value}, a.Type()) - } - } - if a, ok := n.Left.(*StringNode); ok { - if b, ok := n.Right.(*StringNode); ok { - patch(&StringNode{Value: a.Value + b.Value}) - } - } - case "-": - if a, ok := n.Left.(*IntegerNode); ok { - if b, ok := n.Right.(*IntegerNode); ok { - patchWithType(&IntegerNode{Value: a.Value - b.Value}, a.Type()) - } - } - case "*": - if a, ok := n.Left.(*IntegerNode); ok { - if b, ok := n.Right.(*IntegerNode); ok { - patchWithType(&IntegerNode{Value: a.Value * b.Value}, a.Type()) - } - } - case "/": - if a, ok := n.Left.(*IntegerNode); ok { - if b, ok := n.Right.(*IntegerNode); ok { - if b.Value == 0 { - fold.err = &file.Error{ - Location: (*node).Location(), - Message: "integer divide by zero", - } - return - } - patchWithType(&IntegerNode{Value: a.Value / b.Value}, a.Type()) - } - } - case "%": - if a, ok := n.Left.(*IntegerNode); ok { - if b, ok := n.Right.(*IntegerNode); ok { - if b.Value == 0 { - fold.err = &file.Error{ - Location: (*node).Location(), - Message: "integer divide by zero", - } - return - } - patch(&IntegerNode{Value: a.Value % b.Value}) - } - } - case "**": - if a, ok := n.Left.(*IntegerNode); ok { - if b, ok := n.Right.(*IntegerNode); ok { - patch(&FloatNode{Value: math.Pow(float64(a.Value), float64(b.Value))}) - } - } - } - - case *ArrayNode: - if len(n.Nodes) > 0 { - - for _, a := range n.Nodes { - if _, ok := a.(*IntegerNode); !ok { - goto string - } - } - { - value := make([]int, len(n.Nodes)) - for i, a := range n.Nodes { - value[i] = a.(*IntegerNode).Value - } - patch(&ConstantNode{Value: value}) - } - - string: - for _, a := range n.Nodes { - if _, ok := a.(*StringNode); !ok { - return - } - } - { - value := make([]string, len(n.Nodes)) - for i, a := range n.Nodes { - value[i] = a.(*StringNode).Value - } - patch(&ConstantNode{Value: value}) - } - - } - } -} diff --git a/vendor/github.com/antonmedv/expr/optimizer/in_array.go b/vendor/github.com/antonmedv/expr/optimizer/in_array.go deleted file mode 100644 index 8156faa..0000000 --- a/vendor/github.com/antonmedv/expr/optimizer/in_array.go +++ /dev/null @@ -1,65 +0,0 @@ -package optimizer - -import ( - "reflect" - - . "github.com/antonmedv/expr/ast" -) - -type inArray struct{} - -func (*inArray) Enter(*Node) {} -func (*inArray) Exit(node *Node) { - switch n := (*node).(type) { - case *BinaryNode: - if n.Operator == "in" || n.Operator == "not in" { - if array, ok := n.Right.(*ArrayNode); ok { - if len(array.Nodes) > 0 { - t := n.Left.Type() - if t == nil || t.Kind() != reflect.Int { - // This optimization can be only performed if left side is int type, - // as runtime.in func uses reflect.Map.MapIndex and keys of map must, - // be same as checked value type. - goto string - } - - for _, a := range array.Nodes { - if _, ok := a.(*IntegerNode); !ok { - goto string - } - } - { - value := make(map[int]struct{}) - for _, a := range array.Nodes { - value[a.(*IntegerNode).Value] = struct{}{} - } - Patch(node, &BinaryNode{ - Operator: n.Operator, - Left: n.Left, - Right: &ConstantNode{Value: value}, - }) - } - - string: - for _, a := range array.Nodes { - if _, ok := a.(*StringNode); !ok { - return - } - } - { - value := make(map[string]struct{}) - for _, a := range array.Nodes { - value[a.(*StringNode).Value] = struct{}{} - } - Patch(node, &BinaryNode{ - Operator: n.Operator, - Left: n.Left, - Right: &ConstantNode{Value: value}, - }) - } - - } - } - } - } -} diff --git a/vendor/github.com/antonmedv/expr/optimizer/in_range.go b/vendor/github.com/antonmedv/expr/optimizer/in_range.go deleted file mode 100644 index 177c919..0000000 --- a/vendor/github.com/antonmedv/expr/optimizer/in_range.go +++ /dev/null @@ -1,41 +0,0 @@ -package optimizer - -import ( - . "github.com/antonmedv/expr/ast" -) - -type inRange struct{} - -func (*inRange) Enter(*Node) {} -func (*inRange) Exit(node *Node) { - switch n := (*node).(type) { - case *BinaryNode: - if n.Operator == "in" || n.Operator == "not in" { - if rng, ok := n.Right.(*BinaryNode); ok && rng.Operator == ".." { - if from, ok := rng.Left.(*IntegerNode); ok { - if to, ok := rng.Right.(*IntegerNode); ok { - Patch(node, &BinaryNode{ - Operator: "and", - Left: &BinaryNode{ - Operator: ">=", - Left: n.Left, - Right: from, - }, - Right: &BinaryNode{ - Operator: "<=", - Left: n.Left, - Right: to, - }, - }) - if n.Operator == "not in" { - Patch(node, &UnaryNode{ - Operator: "not", - Node: *node, - }) - } - } - } - } - } - } -} diff --git a/vendor/github.com/antonmedv/expr/optimizer/optimizer.go b/vendor/github.com/antonmedv/expr/optimizer/optimizer.go deleted file mode 100644 index 738348d..0000000 --- a/vendor/github.com/antonmedv/expr/optimizer/optimizer.go +++ /dev/null @@ -1,37 +0,0 @@ -package optimizer - -import ( - . "github.com/antonmedv/expr/ast" - "github.com/antonmedv/expr/conf" -) - -func Optimize(node *Node, config *conf.Config) error { - Walk(node, &inArray{}) - for limit := 1000; limit >= 0; limit-- { - fold := &fold{} - Walk(node, fold) - if fold.err != nil { - return fold.err - } - if !fold.applied { - break - } - } - if config != nil && len(config.ConstExprFns) > 0 { - for limit := 100; limit >= 0; limit-- { - constExpr := &constExpr{ - fns: config.ConstExprFns, - } - Walk(node, constExpr) - if constExpr.err != nil { - return constExpr.err - } - if !constExpr.applied { - break - } - } - } - Walk(node, &inRange{}) - Walk(node, &constRange{}) - return nil -} diff --git a/vendor/github.com/antonmedv/expr/parser/lexer/lexer.go b/vendor/github.com/antonmedv/expr/parser/lexer/lexer.go deleted file mode 100644 index 6e4848a..0000000 --- a/vendor/github.com/antonmedv/expr/parser/lexer/lexer.go +++ /dev/null @@ -1,212 +0,0 @@ -package lexer - -import ( - "fmt" - "strings" - "unicode/utf8" - - "github.com/antonmedv/expr/file" -) - -func Lex(source *file.Source) ([]Token, error) { - l := &lexer{ - input: source.Content(), - tokens: make([]Token, 0), - } - - l.loc = file.Location{Line: 1, Column: 0} - l.prev = l.loc - l.startLoc = l.loc - - for state := root; state != nil; { - state = state(l) - } - - if l.err != nil { - return nil, l.err.Bind(source) - } - - return l.tokens, nil -} - -type lexer struct { - input string - tokens []Token - start, end int // current position in input - width int // last rune width - startLoc file.Location // start location - prev, loc file.Location // prev location of end location, end location - err *file.Error -} - -const eof rune = -1 - -func (l *lexer) next() rune { - if l.end >= len(l.input) { - l.width = 0 - return eof - } - r, w := utf8.DecodeRuneInString(l.input[l.end:]) - l.width = w - l.end += w - - l.prev = l.loc - if r == '\n' { - l.loc.Line++ - l.loc.Column = 0 - } else { - l.loc.Column++ - } - - return r -} - -func (l *lexer) peek() rune { - r := l.next() - l.backup() - return r -} - -func (l *lexer) backup() { - l.end -= l.width - l.loc = l.prev -} - -func (l *lexer) emit(t Kind) { - l.emitValue(t, l.word()) -} - -func (l *lexer) emitValue(t Kind, value string) { - l.tokens = append(l.tokens, Token{ - Location: l.startLoc, - Kind: t, - Value: value, - }) - l.start = l.end - l.startLoc = l.loc -} - -func (l *lexer) emitEOF() { - l.tokens = append(l.tokens, Token{ - Location: l.prev, // Point to previous position for better error messages. - Kind: EOF, - }) - l.start = l.end - l.startLoc = l.loc -} - -func (l *lexer) word() string { - return l.input[l.start:l.end] -} - -func (l *lexer) ignore() { - l.start = l.end - l.startLoc = l.loc -} - -func (l *lexer) accept(valid string) bool { - if strings.ContainsRune(valid, l.next()) { - return true - } - l.backup() - return false -} - -func (l *lexer) acceptRun(valid string) { - for strings.ContainsRune(valid, l.next()) { - } - l.backup() -} - -func (l *lexer) acceptWord(word string) bool { - pos, loc, prev := l.end, l.loc, l.prev - - // Skip spaces (U+0020) if any - r := l.peek() - for ; r == ' '; r = l.peek() { - l.next() - } - - for _, ch := range word { - if l.next() != ch { - l.end, l.loc, l.prev = pos, loc, prev - return false - } - } - if r = l.peek(); r != ' ' && r != eof { - l.end, l.loc, l.prev = pos, loc, prev - return false - } - - return true -} - -func (l *lexer) error(format string, args ...interface{}) stateFn { - if l.err == nil { // show first error - l.err = &file.Error{ - Location: l.loc, - Message: fmt.Sprintf(format, args...), - } - } - return nil -} - -func digitVal(ch rune) int { - switch { - case '0' <= ch && ch <= '9': - return int(ch - '0') - case 'a' <= lower(ch) && lower(ch) <= 'f': - return int(lower(ch) - 'a' + 10) - } - return 16 // larger than any legal digit val -} - -func lower(ch rune) rune { return ('a' - 'A') | ch } // returns lower-case ch iff ch is ASCII letter - -func (l *lexer) scanDigits(ch rune, base, n int) rune { - for n > 0 && digitVal(ch) < base { - ch = l.next() - n-- - } - if n > 0 { - l.error("invalid char escape") - } - return ch -} - -func (l *lexer) scanEscape(quote rune) rune { - ch := l.next() // read character after '/' - switch ch { - case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote: - // nothing to do - ch = l.next() - case '0', '1', '2', '3', '4', '5', '6', '7': - ch = l.scanDigits(ch, 8, 3) - case 'x': - ch = l.scanDigits(l.next(), 16, 2) - case 'u': - ch = l.scanDigits(l.next(), 16, 4) - case 'U': - ch = l.scanDigits(l.next(), 16, 8) - default: - l.error("invalid char escape") - } - return ch -} - -func (l *lexer) scanString(quote rune) (n int) { - ch := l.next() // read character after quote - for ch != quote { - if ch == '\n' || ch == eof { - l.error("literal not terminated") - return - } - if ch == '\\' { - ch = l.scanEscape(quote) - } else { - ch = l.next() - } - n++ - } - return -} diff --git a/vendor/github.com/antonmedv/expr/parser/lexer/state.go b/vendor/github.com/antonmedv/expr/parser/lexer/state.go deleted file mode 100644 index 0d4bece..0000000 --- a/vendor/github.com/antonmedv/expr/parser/lexer/state.go +++ /dev/null @@ -1,148 +0,0 @@ -package lexer - -import ( - "strings" -) - -type stateFn func(*lexer) stateFn - -func root(l *lexer) stateFn { - switch r := l.next(); { - case r == eof: - l.emitEOF() - return nil - case IsSpace(r): - l.ignore() - return root - case r == '\'' || r == '"': - l.scanString(r) - str, err := unescape(l.word()) - if err != nil { - l.error("%v", err) - } - l.emitValue(String, str) - case '0' <= r && r <= '9': - l.backup() - return number - case r == '?': - if l.peek() == '.' { - return nilsafe - } - l.emit(Operator) - case strings.ContainsRune("([{", r): - l.emit(Bracket) - case strings.ContainsRune(")]}", r): - l.emit(Bracket) - case strings.ContainsRune("#,?:%+-/", r): // single rune operator - l.emit(Operator) - case strings.ContainsRune("&|!=*<>", r): // possible double rune operator - l.accept("&|=*") - l.emit(Operator) - case r == '.': - l.backup() - return dot - case IsAlphaNumeric(r): - l.backup() - return identifier - default: - return l.error("unrecognized character: %#U", r) - } - return root -} - -func number(l *lexer) stateFn { - if !l.scanNumber() { - return l.error("bad number syntax: %q", l.word()) - } - l.emit(Number) - return root -} - -func (l *lexer) scanNumber() bool { - digits := "0123456789_" - // Is it hex? - if l.accept("0") { - // Note: Leading 0 does not mean octal in floats. - if l.accept("xX") { - digits = "0123456789abcdefABCDEF_" - } else if l.accept("oO") { - digits = "01234567_" - } else if l.accept("bB") { - digits = "01_" - } - } - l.acceptRun(digits) - loc, prev, end := l.loc, l.prev, l.end - if l.accept(".") { - // Lookup for .. operator: if after dot there is another dot (1..2), it maybe a range operator. - if l.peek() == '.' { - // We can't backup() here, as it would require two backups, - // and backup() func supports only one for now. So, save and - // restore it here. - l.loc, l.prev, l.end = loc, prev, end - return true - } - l.acceptRun(digits) - } - if l.accept("eE") { - l.accept("+-") - l.acceptRun(digits) - } - // Next thing mustn't be alphanumeric. - if IsAlphaNumeric(l.peek()) { - l.next() - return false - } - return true -} - -func dot(l *lexer) stateFn { - l.next() - if l.accept("0123456789") { - l.backup() - return number - } - l.accept(".") - l.emit(Operator) - return root -} - -func nilsafe(l *lexer) stateFn { - l.next() - l.accept("?.") - l.emit(Operator) - return root -} - -func identifier(l *lexer) stateFn { -loop: - for { - switch r := l.next(); { - case IsAlphaNumeric(r): - // absorb - default: - l.backup() - switch l.word() { - case "not": - return not - case "in", "or", "and", "matches", "contains", "startsWith", "endsWith": - l.emit(Operator) - default: - l.emit(Identifier) - } - break loop - } - } - return root -} - -func not(l *lexer) stateFn { - switch l.acceptWord("in") { - case true: - l.emitValue(Operator, "not in") - case false: - l.emitValue(Operator, "not") - } - - return root -} diff --git a/vendor/github.com/antonmedv/expr/parser/lexer/token.go b/vendor/github.com/antonmedv/expr/parser/lexer/token.go deleted file mode 100644 index 8917b26..0000000 --- a/vendor/github.com/antonmedv/expr/parser/lexer/token.go +++ /dev/null @@ -1,47 +0,0 @@ -package lexer - -import ( - "fmt" - - "github.com/antonmedv/expr/file" -) - -type Kind string - -const ( - Identifier Kind = "Identifier" - Number Kind = "Number" - String Kind = "String" - Operator Kind = "Operator" - Bracket Kind = "Bracket" - EOF Kind = "EOF" -) - -type Token struct { - file.Location - Kind Kind - Value string -} - -func (t Token) String() string { - if t.Value == "" { - return string(t.Kind) - } - return fmt.Sprintf("%s(%#v)", t.Kind, t.Value) -} - -func (t Token) Is(kind Kind, values ...string) bool { - if len(values) == 0 { - return kind == t.Kind - } - - for _, v := range values { - if v == t.Value { - goto found - } - } - return false - -found: - return kind == t.Kind -} diff --git a/vendor/github.com/antonmedv/expr/parser/lexer/utils.go b/vendor/github.com/antonmedv/expr/parser/lexer/utils.go deleted file mode 100644 index 72e3cf2..0000000 --- a/vendor/github.com/antonmedv/expr/parser/lexer/utils.go +++ /dev/null @@ -1,194 +0,0 @@ -package lexer - -import ( - "fmt" - "strings" - "unicode" - "unicode/utf8" -) - -func IsSpace(r rune) bool { - return unicode.IsSpace(r) -} - -func IsAlphaNumeric(r rune) bool { - return IsAlphabetic(r) || unicode.IsDigit(r) -} - -func IsAlphabetic(r rune) bool { - return r == '_' || r == '$' || unicode.IsLetter(r) -} - -var ( - newlineNormalizer = strings.NewReplacer("\r\n", "\n", "\r", "\n") -) - -// Unescape takes a quoted string, unquotes, and unescapes it. -func unescape(value string) (string, error) { - // All strings normalize newlines to the \n representation. - value = newlineNormalizer.Replace(value) - n := len(value) - - // Nothing to unescape / decode. - if n < 2 { - return value, fmt.Errorf("unable to unescape string") - } - - // Quoted string of some form, must have same first and last char. - if value[0] != value[n-1] || (value[0] != '"' && value[0] != '\'') { - return value, fmt.Errorf("unable to unescape string") - } - - value = value[1 : n-1] - - // The string contains escape characters. - // The following logic is adapted from `strconv/quote.go` - var runeTmp [utf8.UTFMax]byte - buf := make([]byte, 0, 3*n/2) - for len(value) > 0 { - c, multibyte, rest, err := unescapeChar(value) - if err != nil { - return "", err - } - value = rest - if c < utf8.RuneSelf || !multibyte { - buf = append(buf, byte(c)) - } else { - n := utf8.EncodeRune(runeTmp[:], c) - buf = append(buf, runeTmp[:n]...) - } - } - return string(buf), nil -} - -// unescapeChar takes a string input and returns the following info: -// -// value - the escaped unicode rune at the front of the string. -// multibyte - whether the rune value might require multiple bytes to represent. -// tail - the remainder of the input string. -// err - error value, if the character could not be unescaped. -// -// When multibyte is true the return value may still fit within a single byte, -// but a multibyte conversion is attempted which is more expensive than when the -// value is known to fit within one byte. -func unescapeChar(s string) (value rune, multibyte bool, tail string, err error) { - // 1. Character is not an escape sequence. - switch c := s[0]; { - case c >= utf8.RuneSelf: - r, size := utf8.DecodeRuneInString(s) - return r, true, s[size:], nil - case c != '\\': - return rune(s[0]), false, s[1:], nil - } - - // 2. Last character is the start of an escape sequence. - if len(s) <= 1 { - err = fmt.Errorf("unable to unescape string, found '\\' as last character") - return - } - - c := s[1] - s = s[2:] - // 3. Common escape sequences shared with Google SQL - switch c { - case 'a': - value = '\a' - case 'b': - value = '\b' - case 'f': - value = '\f' - case 'n': - value = '\n' - case 'r': - value = '\r' - case 't': - value = '\t' - case 'v': - value = '\v' - case '\\': - value = '\\' - case '\'': - value = '\'' - case '"': - value = '"' - case '`': - value = '`' - case '?': - value = '?' - - // 4. Unicode escape sequences, reproduced from `strconv/quote.go` - case 'x', 'X', 'u', 'U': - n := 0 - switch c { - case 'x', 'X': - n = 2 - case 'u': - n = 4 - case 'U': - n = 8 - } - var v rune - if len(s) < n { - err = fmt.Errorf("unable to unescape string") - return - } - for j := 0; j < n; j++ { - x, ok := unhex(s[j]) - if !ok { - err = fmt.Errorf("unable to unescape string") - return - } - v = v<<4 | x - } - s = s[n:] - if v > utf8.MaxRune { - err = fmt.Errorf("unable to unescape string") - return - } - value = v - multibyte = true - - // 5. Octal escape sequences, must be three digits \[0-3][0-7][0-7] - case '0', '1', '2', '3': - if len(s) < 2 { - err = fmt.Errorf("unable to unescape octal sequence in string") - return - } - v := rune(c - '0') - for j := 0; j < 2; j++ { - x := s[j] - if x < '0' || x > '7' { - err = fmt.Errorf("unable to unescape octal sequence in string") - return - } - v = v*8 + rune(x-'0') - } - if v > utf8.MaxRune { - err = fmt.Errorf("unable to unescape string") - return - } - value = v - s = s[2:] - multibyte = true - - // Unknown escape sequence. - default: - err = fmt.Errorf("unable to unescape string") - } - - tail = s - return -} - -func unhex(b byte) (rune, bool) { - c := rune(b) - switch { - case '0' <= c && c <= '9': - return c - '0', true - case 'a' <= c && c <= 'f': - return c - 'a' + 10, true - case 'A' <= c && c <= 'F': - return c - 'A' + 10, true - } - return 0, false -} diff --git a/vendor/github.com/antonmedv/expr/parser/parser.go b/vendor/github.com/antonmedv/expr/parser/parser.go deleted file mode 100644 index 821de9d..0000000 --- a/vendor/github.com/antonmedv/expr/parser/parser.go +++ /dev/null @@ -1,588 +0,0 @@ -package parser - -import ( - "fmt" - "regexp" - "strconv" - "strings" - "unicode/utf8" - - . "github.com/antonmedv/expr/ast" - "github.com/antonmedv/expr/file" - . "github.com/antonmedv/expr/parser/lexer" -) - -type associativity int - -const ( - left associativity = iota + 1 - right -) - -type operator struct { - precedence int - associativity associativity -} - -type builtin struct { - arity int -} - -var unaryOperators = map[string]operator{ - "not": {50, left}, - "!": {50, left}, - "-": {500, left}, - "+": {500, left}, -} - -var binaryOperators = map[string]operator{ - "or": {10, left}, - "||": {10, left}, - "and": {15, left}, - "&&": {15, left}, - "==": {20, left}, - "!=": {20, left}, - "<": {20, left}, - ">": {20, left}, - ">=": {20, left}, - "<=": {20, left}, - "not in": {20, left}, - "in": {20, left}, - "matches": {20, left}, - "contains": {20, left}, - "startsWith": {20, left}, - "endsWith": {20, left}, - "..": {25, left}, - "+": {30, left}, - "-": {30, left}, - "*": {60, left}, - "/": {60, left}, - "%": {60, left}, - "**": {70, right}, -} - -var builtins = map[string]builtin{ - "len": {1}, - "all": {2}, - "none": {2}, - "any": {2}, - "one": {2}, - "filter": {2}, - "map": {2}, - "count": {2}, -} - -type parser struct { - tokens []Token - current Token - pos int - err *file.Error - depth int // closure call depth -} - -type Tree struct { - Node Node - Source *file.Source -} - -func Parse(input string) (*Tree, error) { - source := file.NewSource(input) - - tokens, err := Lex(source) - if err != nil { - return nil, err - } - - p := &parser{ - tokens: tokens, - current: tokens[0], - } - - node := p.parseExpression(0) - - if !p.current.Is(EOF) { - p.error("unexpected token %v", p.current) - } - - if p.err != nil { - return nil, p.err.Bind(source) - } - - return &Tree{ - Node: node, - Source: source, - }, nil -} - -func (p *parser) error(format string, args ...interface{}) { - if p.err == nil { // show first error - p.err = &file.Error{ - Location: p.current.Location, - Message: fmt.Sprintf(format, args...), - } - } -} - -func (p *parser) next() { - p.pos++ - if p.pos >= len(p.tokens) { - p.error("unexpected end of expression") - return - } - p.current = p.tokens[p.pos] -} - -func (p *parser) expect(kind Kind, values ...string) { - if p.current.Is(kind, values...) { - p.next() - return - } - p.error("unexpected token %v", p.current) -} - -// parse functions - -func (p *parser) parseExpression(precedence int) Node { - nodeLeft := p.parsePrimary() - - token := p.current - for token.Is(Operator) && p.err == nil { - if op, ok := binaryOperators[token.Value]; ok { - if op.precedence >= precedence { - p.next() - - var nodeRight Node - if op.associativity == left { - nodeRight = p.parseExpression(op.precedence + 1) - } else { - nodeRight = p.parseExpression(op.precedence) - } - - if token.Is(Operator, "matches") { - var r *regexp.Regexp - var err error - - if s, ok := nodeRight.(*StringNode); ok { - r, err = regexp.Compile(s.Value) - if err != nil { - p.error("%v", err) - } - } - nodeLeft = &MatchesNode{ - Regexp: r, - Left: nodeLeft, - Right: nodeRight, - } - nodeLeft.SetLocation(token.Location) - } else { - nodeLeft = &BinaryNode{ - Operator: token.Value, - Left: nodeLeft, - Right: nodeRight, - } - nodeLeft.SetLocation(token.Location) - } - token = p.current - continue - } - } - break - } - - if precedence == 0 { - nodeLeft = p.parseConditionalExpression(nodeLeft) - } - - return nodeLeft -} - -func (p *parser) parsePrimary() Node { - token := p.current - - if token.Is(Operator) { - if op, ok := unaryOperators[token.Value]; ok { - p.next() - expr := p.parseExpression(op.precedence) - node := &UnaryNode{ - Operator: token.Value, - Node: expr, - } - node.SetLocation(token.Location) - return p.parsePostfixExpression(node) - } - } - - if token.Is(Bracket, "(") { - p.next() - expr := p.parseExpression(0) - p.expect(Bracket, ")") // "an opened parenthesis is not properly closed" - return p.parsePostfixExpression(expr) - } - - if p.depth > 0 { - if token.Is(Operator, "#") || token.Is(Operator, ".") { - if token.Is(Operator, "#") { - p.next() - } - node := &PointerNode{} - node.SetLocation(token.Location) - return p.parsePostfixExpression(node) - } - } else { - if token.Is(Operator, "#") || token.Is(Operator, ".") { - p.error("cannot use pointer accessor outside closure") - } - } - - return p.parsePrimaryExpression() -} - -func (p *parser) parseConditionalExpression(node Node) Node { - var expr1, expr2 Node - for p.current.Is(Operator, "?") && p.err == nil { - p.next() - - if !p.current.Is(Operator, ":") { - expr1 = p.parseExpression(0) - p.expect(Operator, ":") - expr2 = p.parseExpression(0) - } else { - p.next() - expr1 = node - expr2 = p.parseExpression(0) - } - - node = &ConditionalNode{ - Cond: node, - Exp1: expr1, - Exp2: expr2, - } - } - return node -} - -func (p *parser) parsePrimaryExpression() Node { - var node Node - token := p.current - - switch token.Kind { - - case Identifier: - p.next() - switch token.Value { - case "true": - node := &BoolNode{Value: true} - node.SetLocation(token.Location) - return node - case "false": - node := &BoolNode{Value: false} - node.SetLocation(token.Location) - return node - case "nil": - node := &NilNode{} - node.SetLocation(token.Location) - return node - default: - node = p.parseIdentifierExpression(token, p.current) - } - - case Number: - p.next() - value := strings.Replace(token.Value, "_", "", -1) - if strings.ContainsAny(value, ".eE") { - number, err := strconv.ParseFloat(value, 64) - if err != nil { - p.error("invalid float literal: %v", err) - } - node := &FloatNode{Value: number} - node.SetLocation(token.Location) - return node - } else if strings.Contains(value, "x") { - number, err := strconv.ParseInt(value, 0, 64) - if err != nil { - p.error("invalid hex literal: %v", err) - } - node := &IntegerNode{Value: int(number)} - node.SetLocation(token.Location) - return node - } else { - number, err := strconv.ParseInt(value, 10, 64) - if err != nil { - p.error("invalid integer literal: %v", err) - } - node := &IntegerNode{Value: int(number)} - node.SetLocation(token.Location) - return node - } - - case String: - p.next() - node := &StringNode{Value: token.Value} - node.SetLocation(token.Location) - return node - - default: - if token.Is(Bracket, "[") { - node = p.parseArrayExpression(token) - } else if token.Is(Bracket, "{") { - node = p.parseMapExpression(token) - } else { - p.error("unexpected token %v", token) - } - } - - return p.parsePostfixExpression(node) -} - -func (p *parser) parseIdentifierExpression(token, next Token) Node { - var node Node - if p.current.Is(Bracket, "(") { - var arguments []Node - - if b, ok := builtins[token.Value]; ok { - p.expect(Bracket, "(") - // TODO: Add builtins signatures. - if b.arity == 1 { - arguments = make([]Node, 1) - arguments[0] = p.parseExpression(0) - } else if b.arity == 2 { - arguments = make([]Node, 2) - arguments[0] = p.parseExpression(0) - p.expect(Operator, ",") - arguments[1] = p.parseClosure() - } - p.expect(Bracket, ")") - - node = &BuiltinNode{ - Name: token.Value, - Arguments: arguments, - } - node.SetLocation(token.Location) - } else { - arguments = p.parseArguments() - node = &FunctionNode{ - Name: token.Value, - Arguments: arguments, - } - node.SetLocation(token.Location) - } - } else { - var nilsafe bool - if next.Value == "?." { - nilsafe = true - } - node = &IdentifierNode{Value: token.Value, NilSafe: nilsafe} - node.SetLocation(token.Location) - } - return node -} - -func (p *parser) parseClosure() Node { - token := p.current - p.expect(Bracket, "{") - - p.depth++ - node := p.parseExpression(0) - p.depth-- - - p.expect(Bracket, "}") - closure := &ClosureNode{ - Node: node, - } - closure.SetLocation(token.Location) - return closure -} - -func (p *parser) parseArrayExpression(token Token) Node { - nodes := make([]Node, 0) - - p.expect(Bracket, "[") - for !p.current.Is(Bracket, "]") && p.err == nil { - if len(nodes) > 0 { - p.expect(Operator, ",") - if p.current.Is(Bracket, "]") { - goto end - } - } - node := p.parseExpression(0) - nodes = append(nodes, node) - } -end: - p.expect(Bracket, "]") - - node := &ArrayNode{Nodes: nodes} - node.SetLocation(token.Location) - return node -} - -func (p *parser) parseMapExpression(token Token) Node { - p.expect(Bracket, "{") - - nodes := make([]Node, 0) - for !p.current.Is(Bracket, "}") && p.err == nil { - if len(nodes) > 0 { - p.expect(Operator, ",") - if p.current.Is(Bracket, "}") { - goto end - } - if p.current.Is(Operator, ",") { - p.error("unexpected token %v", p.current) - } - } - - var key Node - // a map key can be: - // * a number - // * a string - // * a identifier, which is equivalent to a string - // * an expression, which must be enclosed in parentheses -- (1 + 2) - if p.current.Is(Number) || p.current.Is(String) || p.current.Is(Identifier) { - key = &StringNode{Value: p.current.Value} - key.SetLocation(token.Location) - p.next() - } else if p.current.Is(Bracket, "(") { - key = p.parseExpression(0) - } else { - p.error("a map key must be a quoted string, a number, a identifier, or an expression enclosed in parentheses (unexpected token %v)", p.current) - } - - p.expect(Operator, ":") - - node := p.parseExpression(0) - pair := &PairNode{Key: key, Value: node} - pair.SetLocation(token.Location) - nodes = append(nodes, pair) - } - -end: - p.expect(Bracket, "}") - - node := &MapNode{Pairs: nodes} - node.SetLocation(token.Location) - return node -} - -func (p *parser) parsePostfixExpression(node Node) Node { - token := p.current - var nilsafe bool - for (token.Is(Operator) || token.Is(Bracket)) && p.err == nil { - if token.Value == "." || token.Value == "?." { - if token.Value == "?." { - nilsafe = true - } - p.next() - - token = p.current - p.next() - - if token.Kind != Identifier && - // Operators like "not" and "matches" are valid methods or property names. - (token.Kind != Operator || !isValidIdentifier(token.Value)) { - p.error("expected name") - } - - if p.current.Is(Bracket, "(") { - arguments := p.parseArguments() - node = &MethodNode{ - Node: node, - Method: token.Value, - Arguments: arguments, - NilSafe: nilsafe, - } - node.SetLocation(token.Location) - } else { - node = &PropertyNode{ - Node: node, - Property: token.Value, - NilSafe: nilsafe, - } - node.SetLocation(token.Location) - } - - } else if token.Value == "[" { - p.next() - var from, to Node - - if p.current.Is(Operator, ":") { // slice without from [:1] - p.next() - - if !p.current.Is(Bracket, "]") { // slice without from and to [:] - to = p.parseExpression(0) - } - - node = &SliceNode{ - Node: node, - To: to, - } - node.SetLocation(token.Location) - p.expect(Bracket, "]") - - } else { - - from = p.parseExpression(0) - - if p.current.Is(Operator, ":") { - p.next() - - if !p.current.Is(Bracket, "]") { // slice without to [1:] - to = p.parseExpression(0) - } - - node = &SliceNode{ - Node: node, - From: from, - To: to, - } - node.SetLocation(token.Location) - p.expect(Bracket, "]") - - } else { - // Slice operator [:] was not found, it should by just index node. - - node = &IndexNode{ - Node: node, - Index: from, - } - node.SetLocation(token.Location) - p.expect(Bracket, "]") - } - } - } else { - break - } - - token = p.current - } - return node -} - -func isValidIdentifier(str string) bool { - if len(str) == 0 { - return false - } - h, w := utf8.DecodeRuneInString(str) - if !IsAlphabetic(h) { - return false - } - for _, r := range str[w:] { - if !IsAlphaNumeric(r) { - return false - } - } - return true -} - -func (p *parser) parseArguments() []Node { - p.expect(Bracket, "(") - nodes := make([]Node, 0) - for !p.current.Is(Bracket, ")") && p.err == nil { - if len(nodes) > 0 { - p.expect(Operator, ",") - } - node := p.parseExpression(0) - nodes = append(nodes, node) - } - p.expect(Bracket, ")") - - return nodes -} diff --git a/vendor/github.com/antonmedv/expr/vm/helpers.go b/vendor/github.com/antonmedv/expr/vm/helpers.go deleted file mode 100644 index 775b0e7..0000000 --- a/vendor/github.com/antonmedv/expr/vm/helpers.go +++ /dev/null @@ -1,3247 +0,0 @@ -// Code generated by vm/generate/main.go. DO NOT EDIT. - -package vm - -import ( - "fmt" - "reflect" -) - -func equal(a, b interface{}) interface{} { - switch x := a.(type) { - case uint: - switch y := b.(type) { - case uint: - return x == y - case uint8: - return uint8(x) == y - case uint16: - return uint16(x) == y - case uint32: - return uint32(x) == y - case uint64: - return uint64(x) == y - case int: - return int(x) == y - case int8: - return int8(x) == y - case int16: - return int16(x) == y - case int32: - return int32(x) == y - case int64: - return int64(x) == y - case float32: - return float32(x) == y - case float64: - return float64(x) == y - } - case uint8: - switch y := b.(type) { - case uint: - return x == uint8(y) - case uint8: - return x == y - case uint16: - return uint16(x) == y - case uint32: - return uint32(x) == y - case uint64: - return uint64(x) == y - case int: - return int(x) == y - case int8: - return int8(x) == y - case int16: - return int16(x) == y - case int32: - return int32(x) == y - case int64: - return int64(x) == y - case float32: - return float32(x) == y - case float64: - return float64(x) == y - } - case uint16: - switch y := b.(type) { - case uint: - return x == uint16(y) - case uint8: - return x == uint16(y) - case uint16: - return x == y - case uint32: - return uint32(x) == y - case uint64: - return uint64(x) == y - case int: - return int(x) == y - case int8: - return int8(x) == y - case int16: - return int16(x) == y - case int32: - return int32(x) == y - case int64: - return int64(x) == y - case float32: - return float32(x) == y - case float64: - return float64(x) == y - } - case uint32: - switch y := b.(type) { - case uint: - return x == uint32(y) - case uint8: - return x == uint32(y) - case uint16: - return x == uint32(y) - case uint32: - return x == y - case uint64: - return uint64(x) == y - case int: - return int(x) == y - case int8: - return int8(x) == y - case int16: - return int16(x) == y - case int32: - return int32(x) == y - case int64: - return int64(x) == y - case float32: - return float32(x) == y - case float64: - return float64(x) == y - } - case uint64: - switch y := b.(type) { - case uint: - return x == uint64(y) - case uint8: - return x == uint64(y) - case uint16: - return x == uint64(y) - case uint32: - return x == uint64(y) - case uint64: - return x == y - case int: - return int(x) == y - case int8: - return int8(x) == y - case int16: - return int16(x) == y - case int32: - return int32(x) == y - case int64: - return int64(x) == y - case float32: - return float32(x) == y - case float64: - return float64(x) == y - } - case int: - switch y := b.(type) { - case uint: - return x == int(y) - case uint8: - return x == int(y) - case uint16: - return x == int(y) - case uint32: - return x == int(y) - case uint64: - return x == int(y) - case int: - return x == y - case int8: - return int8(x) == y - case int16: - return int16(x) == y - case int32: - return int32(x) == y - case int64: - return int64(x) == y - case float32: - return float32(x) == y - case float64: - return float64(x) == y - } - case int8: - switch y := b.(type) { - case uint: - return x == int8(y) - case uint8: - return x == int8(y) - case uint16: - return x == int8(y) - case uint32: - return x == int8(y) - case uint64: - return x == int8(y) - case int: - return x == int8(y) - case int8: - return x == y - case int16: - return int16(x) == y - case int32: - return int32(x) == y - case int64: - return int64(x) == y - case float32: - return float32(x) == y - case float64: - return float64(x) == y - } - case int16: - switch y := b.(type) { - case uint: - return x == int16(y) - case uint8: - return x == int16(y) - case uint16: - return x == int16(y) - case uint32: - return x == int16(y) - case uint64: - return x == int16(y) - case int: - return x == int16(y) - case int8: - return x == int16(y) - case int16: - return x == y - case int32: - return int32(x) == y - case int64: - return int64(x) == y - case float32: - return float32(x) == y - case float64: - return float64(x) == y - } - case int32: - switch y := b.(type) { - case uint: - return x == int32(y) - case uint8: - return x == int32(y) - case uint16: - return x == int32(y) - case uint32: - return x == int32(y) - case uint64: - return x == int32(y) - case int: - return x == int32(y) - case int8: - return x == int32(y) - case int16: - return x == int32(y) - case int32: - return x == y - case int64: - return int64(x) == y - case float32: - return float32(x) == y - case float64: - return float64(x) == y - } - case int64: - switch y := b.(type) { - case uint: - return x == int64(y) - case uint8: - return x == int64(y) - case uint16: - return x == int64(y) - case uint32: - return x == int64(y) - case uint64: - return x == int64(y) - case int: - return x == int64(y) - case int8: - return x == int64(y) - case int16: - return x == int64(y) - case int32: - return x == int64(y) - case int64: - return x == y - case float32: - return float32(x) == y - case float64: - return float64(x) == y - } - case float32: - switch y := b.(type) { - case uint: - return x == float32(y) - case uint8: - return x == float32(y) - case uint16: - return x == float32(y) - case uint32: - return x == float32(y) - case uint64: - return x == float32(y) - case int: - return x == float32(y) - case int8: - return x == float32(y) - case int16: - return x == float32(y) - case int32: - return x == float32(y) - case int64: - return x == float32(y) - case float32: - return x == y - case float64: - return float64(x) == y - } - case float64: - switch y := b.(type) { - case uint: - return x == float64(y) - case uint8: - return x == float64(y) - case uint16: - return x == float64(y) - case uint32: - return x == float64(y) - case uint64: - return x == float64(y) - case int: - return x == float64(y) - case int8: - return x == float64(y) - case int16: - return x == float64(y) - case int32: - return x == float64(y) - case int64: - return x == float64(y) - case float32: - return x == float64(y) - case float64: - return x == y - } - case string: - switch y := b.(type) { - case string: - return x == y - } - } - if isNil(a) && isNil(b) { - return true - } - return reflect.DeepEqual(a, b) -} - -func less(a, b interface{}) interface{} { - switch x := a.(type) { - case uint: - switch y := b.(type) { - case uint: - return x < y - case uint8: - return uint8(x) < y - case uint16: - return uint16(x) < y - case uint32: - return uint32(x) < y - case uint64: - return uint64(x) < y - case int: - return int(x) < y - case int8: - return int8(x) < y - case int16: - return int16(x) < y - case int32: - return int32(x) < y - case int64: - return int64(x) < y - case float32: - return float32(x) < y - case float64: - return float64(x) < y - } - case uint8: - switch y := b.(type) { - case uint: - return x < uint8(y) - case uint8: - return x < y - case uint16: - return uint16(x) < y - case uint32: - return uint32(x) < y - case uint64: - return uint64(x) < y - case int: - return int(x) < y - case int8: - return int8(x) < y - case int16: - return int16(x) < y - case int32: - return int32(x) < y - case int64: - return int64(x) < y - case float32: - return float32(x) < y - case float64: - return float64(x) < y - } - case uint16: - switch y := b.(type) { - case uint: - return x < uint16(y) - case uint8: - return x < uint16(y) - case uint16: - return x < y - case uint32: - return uint32(x) < y - case uint64: - return uint64(x) < y - case int: - return int(x) < y - case int8: - return int8(x) < y - case int16: - return int16(x) < y - case int32: - return int32(x) < y - case int64: - return int64(x) < y - case float32: - return float32(x) < y - case float64: - return float64(x) < y - } - case uint32: - switch y := b.(type) { - case uint: - return x < uint32(y) - case uint8: - return x < uint32(y) - case uint16: - return x < uint32(y) - case uint32: - return x < y - case uint64: - return uint64(x) < y - case int: - return int(x) < y - case int8: - return int8(x) < y - case int16: - return int16(x) < y - case int32: - return int32(x) < y - case int64: - return int64(x) < y - case float32: - return float32(x) < y - case float64: - return float64(x) < y - } - case uint64: - switch y := b.(type) { - case uint: - return x < uint64(y) - case uint8: - return x < uint64(y) - case uint16: - return x < uint64(y) - case uint32: - return x < uint64(y) - case uint64: - return x < y - case int: - return int(x) < y - case int8: - return int8(x) < y - case int16: - return int16(x) < y - case int32: - return int32(x) < y - case int64: - return int64(x) < y - case float32: - return float32(x) < y - case float64: - return float64(x) < y - } - case int: - switch y := b.(type) { - case uint: - return x < int(y) - case uint8: - return x < int(y) - case uint16: - return x < int(y) - case uint32: - return x < int(y) - case uint64: - return x < int(y) - case int: - return x < y - case int8: - return int8(x) < y - case int16: - return int16(x) < y - case int32: - return int32(x) < y - case int64: - return int64(x) < y - case float32: - return float32(x) < y - case float64: - return float64(x) < y - } - case int8: - switch y := b.(type) { - case uint: - return x < int8(y) - case uint8: - return x < int8(y) - case uint16: - return x < int8(y) - case uint32: - return x < int8(y) - case uint64: - return x < int8(y) - case int: - return x < int8(y) - case int8: - return x < y - case int16: - return int16(x) < y - case int32: - return int32(x) < y - case int64: - return int64(x) < y - case float32: - return float32(x) < y - case float64: - return float64(x) < y - } - case int16: - switch y := b.(type) { - case uint: - return x < int16(y) - case uint8: - return x < int16(y) - case uint16: - return x < int16(y) - case uint32: - return x < int16(y) - case uint64: - return x < int16(y) - case int: - return x < int16(y) - case int8: - return x < int16(y) - case int16: - return x < y - case int32: - return int32(x) < y - case int64: - return int64(x) < y - case float32: - return float32(x) < y - case float64: - return float64(x) < y - } - case int32: - switch y := b.(type) { - case uint: - return x < int32(y) - case uint8: - return x < int32(y) - case uint16: - return x < int32(y) - case uint32: - return x < int32(y) - case uint64: - return x < int32(y) - case int: - return x < int32(y) - case int8: - return x < int32(y) - case int16: - return x < int32(y) - case int32: - return x < y - case int64: - return int64(x) < y - case float32: - return float32(x) < y - case float64: - return float64(x) < y - } - case int64: - switch y := b.(type) { - case uint: - return x < int64(y) - case uint8: - return x < int64(y) - case uint16: - return x < int64(y) - case uint32: - return x < int64(y) - case uint64: - return x < int64(y) - case int: - return x < int64(y) - case int8: - return x < int64(y) - case int16: - return x < int64(y) - case int32: - return x < int64(y) - case int64: - return x < y - case float32: - return float32(x) < y - case float64: - return float64(x) < y - } - case float32: - switch y := b.(type) { - case uint: - return x < float32(y) - case uint8: - return x < float32(y) - case uint16: - return x < float32(y) - case uint32: - return x < float32(y) - case uint64: - return x < float32(y) - case int: - return x < float32(y) - case int8: - return x < float32(y) - case int16: - return x < float32(y) - case int32: - return x < float32(y) - case int64: - return x < float32(y) - case float32: - return x < y - case float64: - return float64(x) < y - } - case float64: - switch y := b.(type) { - case uint: - return x < float64(y) - case uint8: - return x < float64(y) - case uint16: - return x < float64(y) - case uint32: - return x < float64(y) - case uint64: - return x < float64(y) - case int: - return x < float64(y) - case int8: - return x < float64(y) - case int16: - return x < float64(y) - case int32: - return x < float64(y) - case int64: - return x < float64(y) - case float32: - return x < float64(y) - case float64: - return x < y - } - case string: - switch y := b.(type) { - case string: - return x < y - } - } - panic(fmt.Sprintf("invalid operation: %T %v %T", a, "<", b)) -} - -func more(a, b interface{}) interface{} { - switch x := a.(type) { - case uint: - switch y := b.(type) { - case uint: - return x > y - case uint8: - return uint8(x) > y - case uint16: - return uint16(x) > y - case uint32: - return uint32(x) > y - case uint64: - return uint64(x) > y - case int: - return int(x) > y - case int8: - return int8(x) > y - case int16: - return int16(x) > y - case int32: - return int32(x) > y - case int64: - return int64(x) > y - case float32: - return float32(x) > y - case float64: - return float64(x) > y - } - case uint8: - switch y := b.(type) { - case uint: - return x > uint8(y) - case uint8: - return x > y - case uint16: - return uint16(x) > y - case uint32: - return uint32(x) > y - case uint64: - return uint64(x) > y - case int: - return int(x) > y - case int8: - return int8(x) > y - case int16: - return int16(x) > y - case int32: - return int32(x) > y - case int64: - return int64(x) > y - case float32: - return float32(x) > y - case float64: - return float64(x) > y - } - case uint16: - switch y := b.(type) { - case uint: - return x > uint16(y) - case uint8: - return x > uint16(y) - case uint16: - return x > y - case uint32: - return uint32(x) > y - case uint64: - return uint64(x) > y - case int: - return int(x) > y - case int8: - return int8(x) > y - case int16: - return int16(x) > y - case int32: - return int32(x) > y - case int64: - return int64(x) > y - case float32: - return float32(x) > y - case float64: - return float64(x) > y - } - case uint32: - switch y := b.(type) { - case uint: - return x > uint32(y) - case uint8: - return x > uint32(y) - case uint16: - return x > uint32(y) - case uint32: - return x > y - case uint64: - return uint64(x) > y - case int: - return int(x) > y - case int8: - return int8(x) > y - case int16: - return int16(x) > y - case int32: - return int32(x) > y - case int64: - return int64(x) > y - case float32: - return float32(x) > y - case float64: - return float64(x) > y - } - case uint64: - switch y := b.(type) { - case uint: - return x > uint64(y) - case uint8: - return x > uint64(y) - case uint16: - return x > uint64(y) - case uint32: - return x > uint64(y) - case uint64: - return x > y - case int: - return int(x) > y - case int8: - return int8(x) > y - case int16: - return int16(x) > y - case int32: - return int32(x) > y - case int64: - return int64(x) > y - case float32: - return float32(x) > y - case float64: - return float64(x) > y - } - case int: - switch y := b.(type) { - case uint: - return x > int(y) - case uint8: - return x > int(y) - case uint16: - return x > int(y) - case uint32: - return x > int(y) - case uint64: - return x > int(y) - case int: - return x > y - case int8: - return int8(x) > y - case int16: - return int16(x) > y - case int32: - return int32(x) > y - case int64: - return int64(x) > y - case float32: - return float32(x) > y - case float64: - return float64(x) > y - } - case int8: - switch y := b.(type) { - case uint: - return x > int8(y) - case uint8: - return x > int8(y) - case uint16: - return x > int8(y) - case uint32: - return x > int8(y) - case uint64: - return x > int8(y) - case int: - return x > int8(y) - case int8: - return x > y - case int16: - return int16(x) > y - case int32: - return int32(x) > y - case int64: - return int64(x) > y - case float32: - return float32(x) > y - case float64: - return float64(x) > y - } - case int16: - switch y := b.(type) { - case uint: - return x > int16(y) - case uint8: - return x > int16(y) - case uint16: - return x > int16(y) - case uint32: - return x > int16(y) - case uint64: - return x > int16(y) - case int: - return x > int16(y) - case int8: - return x > int16(y) - case int16: - return x > y - case int32: - return int32(x) > y - case int64: - return int64(x) > y - case float32: - return float32(x) > y - case float64: - return float64(x) > y - } - case int32: - switch y := b.(type) { - case uint: - return x > int32(y) - case uint8: - return x > int32(y) - case uint16: - return x > int32(y) - case uint32: - return x > int32(y) - case uint64: - return x > int32(y) - case int: - return x > int32(y) - case int8: - return x > int32(y) - case int16: - return x > int32(y) - case int32: - return x > y - case int64: - return int64(x) > y - case float32: - return float32(x) > y - case float64: - return float64(x) > y - } - case int64: - switch y := b.(type) { - case uint: - return x > int64(y) - case uint8: - return x > int64(y) - case uint16: - return x > int64(y) - case uint32: - return x > int64(y) - case uint64: - return x > int64(y) - case int: - return x > int64(y) - case int8: - return x > int64(y) - case int16: - return x > int64(y) - case int32: - return x > int64(y) - case int64: - return x > y - case float32: - return float32(x) > y - case float64: - return float64(x) > y - } - case float32: - switch y := b.(type) { - case uint: - return x > float32(y) - case uint8: - return x > float32(y) - case uint16: - return x > float32(y) - case uint32: - return x > float32(y) - case uint64: - return x > float32(y) - case int: - return x > float32(y) - case int8: - return x > float32(y) - case int16: - return x > float32(y) - case int32: - return x > float32(y) - case int64: - return x > float32(y) - case float32: - return x > y - case float64: - return float64(x) > y - } - case float64: - switch y := b.(type) { - case uint: - return x > float64(y) - case uint8: - return x > float64(y) - case uint16: - return x > float64(y) - case uint32: - return x > float64(y) - case uint64: - return x > float64(y) - case int: - return x > float64(y) - case int8: - return x > float64(y) - case int16: - return x > float64(y) - case int32: - return x > float64(y) - case int64: - return x > float64(y) - case float32: - return x > float64(y) - case float64: - return x > y - } - case string: - switch y := b.(type) { - case string: - return x > y - } - } - panic(fmt.Sprintf("invalid operation: %T %v %T", a, ">", b)) -} - -func lessOrEqual(a, b interface{}) interface{} { - switch x := a.(type) { - case uint: - switch y := b.(type) { - case uint: - return x <= y - case uint8: - return uint8(x) <= y - case uint16: - return uint16(x) <= y - case uint32: - return uint32(x) <= y - case uint64: - return uint64(x) <= y - case int: - return int(x) <= y - case int8: - return int8(x) <= y - case int16: - return int16(x) <= y - case int32: - return int32(x) <= y - case int64: - return int64(x) <= y - case float32: - return float32(x) <= y - case float64: - return float64(x) <= y - } - case uint8: - switch y := b.(type) { - case uint: - return x <= uint8(y) - case uint8: - return x <= y - case uint16: - return uint16(x) <= y - case uint32: - return uint32(x) <= y - case uint64: - return uint64(x) <= y - case int: - return int(x) <= y - case int8: - return int8(x) <= y - case int16: - return int16(x) <= y - case int32: - return int32(x) <= y - case int64: - return int64(x) <= y - case float32: - return float32(x) <= y - case float64: - return float64(x) <= y - } - case uint16: - switch y := b.(type) { - case uint: - return x <= uint16(y) - case uint8: - return x <= uint16(y) - case uint16: - return x <= y - case uint32: - return uint32(x) <= y - case uint64: - return uint64(x) <= y - case int: - return int(x) <= y - case int8: - return int8(x) <= y - case int16: - return int16(x) <= y - case int32: - return int32(x) <= y - case int64: - return int64(x) <= y - case float32: - return float32(x) <= y - case float64: - return float64(x) <= y - } - case uint32: - switch y := b.(type) { - case uint: - return x <= uint32(y) - case uint8: - return x <= uint32(y) - case uint16: - return x <= uint32(y) - case uint32: - return x <= y - case uint64: - return uint64(x) <= y - case int: - return int(x) <= y - case int8: - return int8(x) <= y - case int16: - return int16(x) <= y - case int32: - return int32(x) <= y - case int64: - return int64(x) <= y - case float32: - return float32(x) <= y - case float64: - return float64(x) <= y - } - case uint64: - switch y := b.(type) { - case uint: - return x <= uint64(y) - case uint8: - return x <= uint64(y) - case uint16: - return x <= uint64(y) - case uint32: - return x <= uint64(y) - case uint64: - return x <= y - case int: - return int(x) <= y - case int8: - return int8(x) <= y - case int16: - return int16(x) <= y - case int32: - return int32(x) <= y - case int64: - return int64(x) <= y - case float32: - return float32(x) <= y - case float64: - return float64(x) <= y - } - case int: - switch y := b.(type) { - case uint: - return x <= int(y) - case uint8: - return x <= int(y) - case uint16: - return x <= int(y) - case uint32: - return x <= int(y) - case uint64: - return x <= int(y) - case int: - return x <= y - case int8: - return int8(x) <= y - case int16: - return int16(x) <= y - case int32: - return int32(x) <= y - case int64: - return int64(x) <= y - case float32: - return float32(x) <= y - case float64: - return float64(x) <= y - } - case int8: - switch y := b.(type) { - case uint: - return x <= int8(y) - case uint8: - return x <= int8(y) - case uint16: - return x <= int8(y) - case uint32: - return x <= int8(y) - case uint64: - return x <= int8(y) - case int: - return x <= int8(y) - case int8: - return x <= y - case int16: - return int16(x) <= y - case int32: - return int32(x) <= y - case int64: - return int64(x) <= y - case float32: - return float32(x) <= y - case float64: - return float64(x) <= y - } - case int16: - switch y := b.(type) { - case uint: - return x <= int16(y) - case uint8: - return x <= int16(y) - case uint16: - return x <= int16(y) - case uint32: - return x <= int16(y) - case uint64: - return x <= int16(y) - case int: - return x <= int16(y) - case int8: - return x <= int16(y) - case int16: - return x <= y - case int32: - return int32(x) <= y - case int64: - return int64(x) <= y - case float32: - return float32(x) <= y - case float64: - return float64(x) <= y - } - case int32: - switch y := b.(type) { - case uint: - return x <= int32(y) - case uint8: - return x <= int32(y) - case uint16: - return x <= int32(y) - case uint32: - return x <= int32(y) - case uint64: - return x <= int32(y) - case int: - return x <= int32(y) - case int8: - return x <= int32(y) - case int16: - return x <= int32(y) - case int32: - return x <= y - case int64: - return int64(x) <= y - case float32: - return float32(x) <= y - case float64: - return float64(x) <= y - } - case int64: - switch y := b.(type) { - case uint: - return x <= int64(y) - case uint8: - return x <= int64(y) - case uint16: - return x <= int64(y) - case uint32: - return x <= int64(y) - case uint64: - return x <= int64(y) - case int: - return x <= int64(y) - case int8: - return x <= int64(y) - case int16: - return x <= int64(y) - case int32: - return x <= int64(y) - case int64: - return x <= y - case float32: - return float32(x) <= y - case float64: - return float64(x) <= y - } - case float32: - switch y := b.(type) { - case uint: - return x <= float32(y) - case uint8: - return x <= float32(y) - case uint16: - return x <= float32(y) - case uint32: - return x <= float32(y) - case uint64: - return x <= float32(y) - case int: - return x <= float32(y) - case int8: - return x <= float32(y) - case int16: - return x <= float32(y) - case int32: - return x <= float32(y) - case int64: - return x <= float32(y) - case float32: - return x <= y - case float64: - return float64(x) <= y - } - case float64: - switch y := b.(type) { - case uint: - return x <= float64(y) - case uint8: - return x <= float64(y) - case uint16: - return x <= float64(y) - case uint32: - return x <= float64(y) - case uint64: - return x <= float64(y) - case int: - return x <= float64(y) - case int8: - return x <= float64(y) - case int16: - return x <= float64(y) - case int32: - return x <= float64(y) - case int64: - return x <= float64(y) - case float32: - return x <= float64(y) - case float64: - return x <= y - } - case string: - switch y := b.(type) { - case string: - return x <= y - } - } - panic(fmt.Sprintf("invalid operation: %T %v %T", a, "<=", b)) -} - -func moreOrEqual(a, b interface{}) interface{} { - switch x := a.(type) { - case uint: - switch y := b.(type) { - case uint: - return x >= y - case uint8: - return uint8(x) >= y - case uint16: - return uint16(x) >= y - case uint32: - return uint32(x) >= y - case uint64: - return uint64(x) >= y - case int: - return int(x) >= y - case int8: - return int8(x) >= y - case int16: - return int16(x) >= y - case int32: - return int32(x) >= y - case int64: - return int64(x) >= y - case float32: - return float32(x) >= y - case float64: - return float64(x) >= y - } - case uint8: - switch y := b.(type) { - case uint: - return x >= uint8(y) - case uint8: - return x >= y - case uint16: - return uint16(x) >= y - case uint32: - return uint32(x) >= y - case uint64: - return uint64(x) >= y - case int: - return int(x) >= y - case int8: - return int8(x) >= y - case int16: - return int16(x) >= y - case int32: - return int32(x) >= y - case int64: - return int64(x) >= y - case float32: - return float32(x) >= y - case float64: - return float64(x) >= y - } - case uint16: - switch y := b.(type) { - case uint: - return x >= uint16(y) - case uint8: - return x >= uint16(y) - case uint16: - return x >= y - case uint32: - return uint32(x) >= y - case uint64: - return uint64(x) >= y - case int: - return int(x) >= y - case int8: - return int8(x) >= y - case int16: - return int16(x) >= y - case int32: - return int32(x) >= y - case int64: - return int64(x) >= y - case float32: - return float32(x) >= y - case float64: - return float64(x) >= y - } - case uint32: - switch y := b.(type) { - case uint: - return x >= uint32(y) - case uint8: - return x >= uint32(y) - case uint16: - return x >= uint32(y) - case uint32: - return x >= y - case uint64: - return uint64(x) >= y - case int: - return int(x) >= y - case int8: - return int8(x) >= y - case int16: - return int16(x) >= y - case int32: - return int32(x) >= y - case int64: - return int64(x) >= y - case float32: - return float32(x) >= y - case float64: - return float64(x) >= y - } - case uint64: - switch y := b.(type) { - case uint: - return x >= uint64(y) - case uint8: - return x >= uint64(y) - case uint16: - return x >= uint64(y) - case uint32: - return x >= uint64(y) - case uint64: - return x >= y - case int: - return int(x) >= y - case int8: - return int8(x) >= y - case int16: - return int16(x) >= y - case int32: - return int32(x) >= y - case int64: - return int64(x) >= y - case float32: - return float32(x) >= y - case float64: - return float64(x) >= y - } - case int: - switch y := b.(type) { - case uint: - return x >= int(y) - case uint8: - return x >= int(y) - case uint16: - return x >= int(y) - case uint32: - return x >= int(y) - case uint64: - return x >= int(y) - case int: - return x >= y - case int8: - return int8(x) >= y - case int16: - return int16(x) >= y - case int32: - return int32(x) >= y - case int64: - return int64(x) >= y - case float32: - return float32(x) >= y - case float64: - return float64(x) >= y - } - case int8: - switch y := b.(type) { - case uint: - return x >= int8(y) - case uint8: - return x >= int8(y) - case uint16: - return x >= int8(y) - case uint32: - return x >= int8(y) - case uint64: - return x >= int8(y) - case int: - return x >= int8(y) - case int8: - return x >= y - case int16: - return int16(x) >= y - case int32: - return int32(x) >= y - case int64: - return int64(x) >= y - case float32: - return float32(x) >= y - case float64: - return float64(x) >= y - } - case int16: - switch y := b.(type) { - case uint: - return x >= int16(y) - case uint8: - return x >= int16(y) - case uint16: - return x >= int16(y) - case uint32: - return x >= int16(y) - case uint64: - return x >= int16(y) - case int: - return x >= int16(y) - case int8: - return x >= int16(y) - case int16: - return x >= y - case int32: - return int32(x) >= y - case int64: - return int64(x) >= y - case float32: - return float32(x) >= y - case float64: - return float64(x) >= y - } - case int32: - switch y := b.(type) { - case uint: - return x >= int32(y) - case uint8: - return x >= int32(y) - case uint16: - return x >= int32(y) - case uint32: - return x >= int32(y) - case uint64: - return x >= int32(y) - case int: - return x >= int32(y) - case int8: - return x >= int32(y) - case int16: - return x >= int32(y) - case int32: - return x >= y - case int64: - return int64(x) >= y - case float32: - return float32(x) >= y - case float64: - return float64(x) >= y - } - case int64: - switch y := b.(type) { - case uint: - return x >= int64(y) - case uint8: - return x >= int64(y) - case uint16: - return x >= int64(y) - case uint32: - return x >= int64(y) - case uint64: - return x >= int64(y) - case int: - return x >= int64(y) - case int8: - return x >= int64(y) - case int16: - return x >= int64(y) - case int32: - return x >= int64(y) - case int64: - return x >= y - case float32: - return float32(x) >= y - case float64: - return float64(x) >= y - } - case float32: - switch y := b.(type) { - case uint: - return x >= float32(y) - case uint8: - return x >= float32(y) - case uint16: - return x >= float32(y) - case uint32: - return x >= float32(y) - case uint64: - return x >= float32(y) - case int: - return x >= float32(y) - case int8: - return x >= float32(y) - case int16: - return x >= float32(y) - case int32: - return x >= float32(y) - case int64: - return x >= float32(y) - case float32: - return x >= y - case float64: - return float64(x) >= y - } - case float64: - switch y := b.(type) { - case uint: - return x >= float64(y) - case uint8: - return x >= float64(y) - case uint16: - return x >= float64(y) - case uint32: - return x >= float64(y) - case uint64: - return x >= float64(y) - case int: - return x >= float64(y) - case int8: - return x >= float64(y) - case int16: - return x >= float64(y) - case int32: - return x >= float64(y) - case int64: - return x >= float64(y) - case float32: - return x >= float64(y) - case float64: - return x >= y - } - case string: - switch y := b.(type) { - case string: - return x >= y - } - } - panic(fmt.Sprintf("invalid operation: %T %v %T", a, ">=", b)) -} - -func add(a, b interface{}) interface{} { - switch x := a.(type) { - case uint: - switch y := b.(type) { - case uint: - return x + y - case uint8: - return uint8(x) + y - case uint16: - return uint16(x) + y - case uint32: - return uint32(x) + y - case uint64: - return uint64(x) + y - case int: - return int(x) + y - case int8: - return int8(x) + y - case int16: - return int16(x) + y - case int32: - return int32(x) + y - case int64: - return int64(x) + y - case float32: - return float32(x) + y - case float64: - return float64(x) + y - } - case uint8: - switch y := b.(type) { - case uint: - return x + uint8(y) - case uint8: - return x + y - case uint16: - return uint16(x) + y - case uint32: - return uint32(x) + y - case uint64: - return uint64(x) + y - case int: - return int(x) + y - case int8: - return int8(x) + y - case int16: - return int16(x) + y - case int32: - return int32(x) + y - case int64: - return int64(x) + y - case float32: - return float32(x) + y - case float64: - return float64(x) + y - } - case uint16: - switch y := b.(type) { - case uint: - return x + uint16(y) - case uint8: - return x + uint16(y) - case uint16: - return x + y - case uint32: - return uint32(x) + y - case uint64: - return uint64(x) + y - case int: - return int(x) + y - case int8: - return int8(x) + y - case int16: - return int16(x) + y - case int32: - return int32(x) + y - case int64: - return int64(x) + y - case float32: - return float32(x) + y - case float64: - return float64(x) + y - } - case uint32: - switch y := b.(type) { - case uint: - return x + uint32(y) - case uint8: - return x + uint32(y) - case uint16: - return x + uint32(y) - case uint32: - return x + y - case uint64: - return uint64(x) + y - case int: - return int(x) + y - case int8: - return int8(x) + y - case int16: - return int16(x) + y - case int32: - return int32(x) + y - case int64: - return int64(x) + y - case float32: - return float32(x) + y - case float64: - return float64(x) + y - } - case uint64: - switch y := b.(type) { - case uint: - return x + uint64(y) - case uint8: - return x + uint64(y) - case uint16: - return x + uint64(y) - case uint32: - return x + uint64(y) - case uint64: - return x + y - case int: - return int(x) + y - case int8: - return int8(x) + y - case int16: - return int16(x) + y - case int32: - return int32(x) + y - case int64: - return int64(x) + y - case float32: - return float32(x) + y - case float64: - return float64(x) + y - } - case int: - switch y := b.(type) { - case uint: - return x + int(y) - case uint8: - return x + int(y) - case uint16: - return x + int(y) - case uint32: - return x + int(y) - case uint64: - return x + int(y) - case int: - return x + y - case int8: - return int8(x) + y - case int16: - return int16(x) + y - case int32: - return int32(x) + y - case int64: - return int64(x) + y - case float32: - return float32(x) + y - case float64: - return float64(x) + y - } - case int8: - switch y := b.(type) { - case uint: - return x + int8(y) - case uint8: - return x + int8(y) - case uint16: - return x + int8(y) - case uint32: - return x + int8(y) - case uint64: - return x + int8(y) - case int: - return x + int8(y) - case int8: - return x + y - case int16: - return int16(x) + y - case int32: - return int32(x) + y - case int64: - return int64(x) + y - case float32: - return float32(x) + y - case float64: - return float64(x) + y - } - case int16: - switch y := b.(type) { - case uint: - return x + int16(y) - case uint8: - return x + int16(y) - case uint16: - return x + int16(y) - case uint32: - return x + int16(y) - case uint64: - return x + int16(y) - case int: - return x + int16(y) - case int8: - return x + int16(y) - case int16: - return x + y - case int32: - return int32(x) + y - case int64: - return int64(x) + y - case float32: - return float32(x) + y - case float64: - return float64(x) + y - } - case int32: - switch y := b.(type) { - case uint: - return x + int32(y) - case uint8: - return x + int32(y) - case uint16: - return x + int32(y) - case uint32: - return x + int32(y) - case uint64: - return x + int32(y) - case int: - return x + int32(y) - case int8: - return x + int32(y) - case int16: - return x + int32(y) - case int32: - return x + y - case int64: - return int64(x) + y - case float32: - return float32(x) + y - case float64: - return float64(x) + y - } - case int64: - switch y := b.(type) { - case uint: - return x + int64(y) - case uint8: - return x + int64(y) - case uint16: - return x + int64(y) - case uint32: - return x + int64(y) - case uint64: - return x + int64(y) - case int: - return x + int64(y) - case int8: - return x + int64(y) - case int16: - return x + int64(y) - case int32: - return x + int64(y) - case int64: - return x + y - case float32: - return float32(x) + y - case float64: - return float64(x) + y - } - case float32: - switch y := b.(type) { - case uint: - return x + float32(y) - case uint8: - return x + float32(y) - case uint16: - return x + float32(y) - case uint32: - return x + float32(y) - case uint64: - return x + float32(y) - case int: - return x + float32(y) - case int8: - return x + float32(y) - case int16: - return x + float32(y) - case int32: - return x + float32(y) - case int64: - return x + float32(y) - case float32: - return x + y - case float64: - return float64(x) + y - } - case float64: - switch y := b.(type) { - case uint: - return x + float64(y) - case uint8: - return x + float64(y) - case uint16: - return x + float64(y) - case uint32: - return x + float64(y) - case uint64: - return x + float64(y) - case int: - return x + float64(y) - case int8: - return x + float64(y) - case int16: - return x + float64(y) - case int32: - return x + float64(y) - case int64: - return x + float64(y) - case float32: - return x + float64(y) - case float64: - return x + y - } - case string: - switch y := b.(type) { - case string: - return x + y - } - } - panic(fmt.Sprintf("invalid operation: %T %v %T", a, "+", b)) -} - -func subtract(a, b interface{}) interface{} { - switch x := a.(type) { - case uint: - switch y := b.(type) { - case uint: - return x - y - case uint8: - return uint8(x) - y - case uint16: - return uint16(x) - y - case uint32: - return uint32(x) - y - case uint64: - return uint64(x) - y - case int: - return int(x) - y - case int8: - return int8(x) - y - case int16: - return int16(x) - y - case int32: - return int32(x) - y - case int64: - return int64(x) - y - case float32: - return float32(x) - y - case float64: - return float64(x) - y - } - case uint8: - switch y := b.(type) { - case uint: - return x - uint8(y) - case uint8: - return x - y - case uint16: - return uint16(x) - y - case uint32: - return uint32(x) - y - case uint64: - return uint64(x) - y - case int: - return int(x) - y - case int8: - return int8(x) - y - case int16: - return int16(x) - y - case int32: - return int32(x) - y - case int64: - return int64(x) - y - case float32: - return float32(x) - y - case float64: - return float64(x) - y - } - case uint16: - switch y := b.(type) { - case uint: - return x - uint16(y) - case uint8: - return x - uint16(y) - case uint16: - return x - y - case uint32: - return uint32(x) - y - case uint64: - return uint64(x) - y - case int: - return int(x) - y - case int8: - return int8(x) - y - case int16: - return int16(x) - y - case int32: - return int32(x) - y - case int64: - return int64(x) - y - case float32: - return float32(x) - y - case float64: - return float64(x) - y - } - case uint32: - switch y := b.(type) { - case uint: - return x - uint32(y) - case uint8: - return x - uint32(y) - case uint16: - return x - uint32(y) - case uint32: - return x - y - case uint64: - return uint64(x) - y - case int: - return int(x) - y - case int8: - return int8(x) - y - case int16: - return int16(x) - y - case int32: - return int32(x) - y - case int64: - return int64(x) - y - case float32: - return float32(x) - y - case float64: - return float64(x) - y - } - case uint64: - switch y := b.(type) { - case uint: - return x - uint64(y) - case uint8: - return x - uint64(y) - case uint16: - return x - uint64(y) - case uint32: - return x - uint64(y) - case uint64: - return x - y - case int: - return int(x) - y - case int8: - return int8(x) - y - case int16: - return int16(x) - y - case int32: - return int32(x) - y - case int64: - return int64(x) - y - case float32: - return float32(x) - y - case float64: - return float64(x) - y - } - case int: - switch y := b.(type) { - case uint: - return x - int(y) - case uint8: - return x - int(y) - case uint16: - return x - int(y) - case uint32: - return x - int(y) - case uint64: - return x - int(y) - case int: - return x - y - case int8: - return int8(x) - y - case int16: - return int16(x) - y - case int32: - return int32(x) - y - case int64: - return int64(x) - y - case float32: - return float32(x) - y - case float64: - return float64(x) - y - } - case int8: - switch y := b.(type) { - case uint: - return x - int8(y) - case uint8: - return x - int8(y) - case uint16: - return x - int8(y) - case uint32: - return x - int8(y) - case uint64: - return x - int8(y) - case int: - return x - int8(y) - case int8: - return x - y - case int16: - return int16(x) - y - case int32: - return int32(x) - y - case int64: - return int64(x) - y - case float32: - return float32(x) - y - case float64: - return float64(x) - y - } - case int16: - switch y := b.(type) { - case uint: - return x - int16(y) - case uint8: - return x - int16(y) - case uint16: - return x - int16(y) - case uint32: - return x - int16(y) - case uint64: - return x - int16(y) - case int: - return x - int16(y) - case int8: - return x - int16(y) - case int16: - return x - y - case int32: - return int32(x) - y - case int64: - return int64(x) - y - case float32: - return float32(x) - y - case float64: - return float64(x) - y - } - case int32: - switch y := b.(type) { - case uint: - return x - int32(y) - case uint8: - return x - int32(y) - case uint16: - return x - int32(y) - case uint32: - return x - int32(y) - case uint64: - return x - int32(y) - case int: - return x - int32(y) - case int8: - return x - int32(y) - case int16: - return x - int32(y) - case int32: - return x - y - case int64: - return int64(x) - y - case float32: - return float32(x) - y - case float64: - return float64(x) - y - } - case int64: - switch y := b.(type) { - case uint: - return x - int64(y) - case uint8: - return x - int64(y) - case uint16: - return x - int64(y) - case uint32: - return x - int64(y) - case uint64: - return x - int64(y) - case int: - return x - int64(y) - case int8: - return x - int64(y) - case int16: - return x - int64(y) - case int32: - return x - int64(y) - case int64: - return x - y - case float32: - return float32(x) - y - case float64: - return float64(x) - y - } - case float32: - switch y := b.(type) { - case uint: - return x - float32(y) - case uint8: - return x - float32(y) - case uint16: - return x - float32(y) - case uint32: - return x - float32(y) - case uint64: - return x - float32(y) - case int: - return x - float32(y) - case int8: - return x - float32(y) - case int16: - return x - float32(y) - case int32: - return x - float32(y) - case int64: - return x - float32(y) - case float32: - return x - y - case float64: - return float64(x) - y - } - case float64: - switch y := b.(type) { - case uint: - return x - float64(y) - case uint8: - return x - float64(y) - case uint16: - return x - float64(y) - case uint32: - return x - float64(y) - case uint64: - return x - float64(y) - case int: - return x - float64(y) - case int8: - return x - float64(y) - case int16: - return x - float64(y) - case int32: - return x - float64(y) - case int64: - return x - float64(y) - case float32: - return x - float64(y) - case float64: - return x - y - } - } - panic(fmt.Sprintf("invalid operation: %T %v %T", a, "-", b)) -} - -func multiply(a, b interface{}) interface{} { - switch x := a.(type) { - case uint: - switch y := b.(type) { - case uint: - return x * y - case uint8: - return uint8(x) * y - case uint16: - return uint16(x) * y - case uint32: - return uint32(x) * y - case uint64: - return uint64(x) * y - case int: - return int(x) * y - case int8: - return int8(x) * y - case int16: - return int16(x) * y - case int32: - return int32(x) * y - case int64: - return int64(x) * y - case float32: - return float32(x) * y - case float64: - return float64(x) * y - } - case uint8: - switch y := b.(type) { - case uint: - return x * uint8(y) - case uint8: - return x * y - case uint16: - return uint16(x) * y - case uint32: - return uint32(x) * y - case uint64: - return uint64(x) * y - case int: - return int(x) * y - case int8: - return int8(x) * y - case int16: - return int16(x) * y - case int32: - return int32(x) * y - case int64: - return int64(x) * y - case float32: - return float32(x) * y - case float64: - return float64(x) * y - } - case uint16: - switch y := b.(type) { - case uint: - return x * uint16(y) - case uint8: - return x * uint16(y) - case uint16: - return x * y - case uint32: - return uint32(x) * y - case uint64: - return uint64(x) * y - case int: - return int(x) * y - case int8: - return int8(x) * y - case int16: - return int16(x) * y - case int32: - return int32(x) * y - case int64: - return int64(x) * y - case float32: - return float32(x) * y - case float64: - return float64(x) * y - } - case uint32: - switch y := b.(type) { - case uint: - return x * uint32(y) - case uint8: - return x * uint32(y) - case uint16: - return x * uint32(y) - case uint32: - return x * y - case uint64: - return uint64(x) * y - case int: - return int(x) * y - case int8: - return int8(x) * y - case int16: - return int16(x) * y - case int32: - return int32(x) * y - case int64: - return int64(x) * y - case float32: - return float32(x) * y - case float64: - return float64(x) * y - } - case uint64: - switch y := b.(type) { - case uint: - return x * uint64(y) - case uint8: - return x * uint64(y) - case uint16: - return x * uint64(y) - case uint32: - return x * uint64(y) - case uint64: - return x * y - case int: - return int(x) * y - case int8: - return int8(x) * y - case int16: - return int16(x) * y - case int32: - return int32(x) * y - case int64: - return int64(x) * y - case float32: - return float32(x) * y - case float64: - return float64(x) * y - } - case int: - switch y := b.(type) { - case uint: - return x * int(y) - case uint8: - return x * int(y) - case uint16: - return x * int(y) - case uint32: - return x * int(y) - case uint64: - return x * int(y) - case int: - return x * y - case int8: - return int8(x) * y - case int16: - return int16(x) * y - case int32: - return int32(x) * y - case int64: - return int64(x) * y - case float32: - return float32(x) * y - case float64: - return float64(x) * y - } - case int8: - switch y := b.(type) { - case uint: - return x * int8(y) - case uint8: - return x * int8(y) - case uint16: - return x * int8(y) - case uint32: - return x * int8(y) - case uint64: - return x * int8(y) - case int: - return x * int8(y) - case int8: - return x * y - case int16: - return int16(x) * y - case int32: - return int32(x) * y - case int64: - return int64(x) * y - case float32: - return float32(x) * y - case float64: - return float64(x) * y - } - case int16: - switch y := b.(type) { - case uint: - return x * int16(y) - case uint8: - return x * int16(y) - case uint16: - return x * int16(y) - case uint32: - return x * int16(y) - case uint64: - return x * int16(y) - case int: - return x * int16(y) - case int8: - return x * int16(y) - case int16: - return x * y - case int32: - return int32(x) * y - case int64: - return int64(x) * y - case float32: - return float32(x) * y - case float64: - return float64(x) * y - } - case int32: - switch y := b.(type) { - case uint: - return x * int32(y) - case uint8: - return x * int32(y) - case uint16: - return x * int32(y) - case uint32: - return x * int32(y) - case uint64: - return x * int32(y) - case int: - return x * int32(y) - case int8: - return x * int32(y) - case int16: - return x * int32(y) - case int32: - return x * y - case int64: - return int64(x) * y - case float32: - return float32(x) * y - case float64: - return float64(x) * y - } - case int64: - switch y := b.(type) { - case uint: - return x * int64(y) - case uint8: - return x * int64(y) - case uint16: - return x * int64(y) - case uint32: - return x * int64(y) - case uint64: - return x * int64(y) - case int: - return x * int64(y) - case int8: - return x * int64(y) - case int16: - return x * int64(y) - case int32: - return x * int64(y) - case int64: - return x * y - case float32: - return float32(x) * y - case float64: - return float64(x) * y - } - case float32: - switch y := b.(type) { - case uint: - return x * float32(y) - case uint8: - return x * float32(y) - case uint16: - return x * float32(y) - case uint32: - return x * float32(y) - case uint64: - return x * float32(y) - case int: - return x * float32(y) - case int8: - return x * float32(y) - case int16: - return x * float32(y) - case int32: - return x * float32(y) - case int64: - return x * float32(y) - case float32: - return x * y - case float64: - return float64(x) * y - } - case float64: - switch y := b.(type) { - case uint: - return x * float64(y) - case uint8: - return x * float64(y) - case uint16: - return x * float64(y) - case uint32: - return x * float64(y) - case uint64: - return x * float64(y) - case int: - return x * float64(y) - case int8: - return x * float64(y) - case int16: - return x * float64(y) - case int32: - return x * float64(y) - case int64: - return x * float64(y) - case float32: - return x * float64(y) - case float64: - return x * y - } - } - panic(fmt.Sprintf("invalid operation: %T %v %T", a, "*", b)) -} - -func divide(a, b interface{}) interface{} { - switch x := a.(type) { - case uint: - switch y := b.(type) { - case uint: - return x / y - case uint8: - return uint8(x) / y - case uint16: - return uint16(x) / y - case uint32: - return uint32(x) / y - case uint64: - return uint64(x) / y - case int: - return int(x) / y - case int8: - return int8(x) / y - case int16: - return int16(x) / y - case int32: - return int32(x) / y - case int64: - return int64(x) / y - case float32: - return float32(x) / y - case float64: - return float64(x) / y - } - case uint8: - switch y := b.(type) { - case uint: - return x / uint8(y) - case uint8: - return x / y - case uint16: - return uint16(x) / y - case uint32: - return uint32(x) / y - case uint64: - return uint64(x) / y - case int: - return int(x) / y - case int8: - return int8(x) / y - case int16: - return int16(x) / y - case int32: - return int32(x) / y - case int64: - return int64(x) / y - case float32: - return float32(x) / y - case float64: - return float64(x) / y - } - case uint16: - switch y := b.(type) { - case uint: - return x / uint16(y) - case uint8: - return x / uint16(y) - case uint16: - return x / y - case uint32: - return uint32(x) / y - case uint64: - return uint64(x) / y - case int: - return int(x) / y - case int8: - return int8(x) / y - case int16: - return int16(x) / y - case int32: - return int32(x) / y - case int64: - return int64(x) / y - case float32: - return float32(x) / y - case float64: - return float64(x) / y - } - case uint32: - switch y := b.(type) { - case uint: - return x / uint32(y) - case uint8: - return x / uint32(y) - case uint16: - return x / uint32(y) - case uint32: - return x / y - case uint64: - return uint64(x) / y - case int: - return int(x) / y - case int8: - return int8(x) / y - case int16: - return int16(x) / y - case int32: - return int32(x) / y - case int64: - return int64(x) / y - case float32: - return float32(x) / y - case float64: - return float64(x) / y - } - case uint64: - switch y := b.(type) { - case uint: - return x / uint64(y) - case uint8: - return x / uint64(y) - case uint16: - return x / uint64(y) - case uint32: - return x / uint64(y) - case uint64: - return x / y - case int: - return int(x) / y - case int8: - return int8(x) / y - case int16: - return int16(x) / y - case int32: - return int32(x) / y - case int64: - return int64(x) / y - case float32: - return float32(x) / y - case float64: - return float64(x) / y - } - case int: - switch y := b.(type) { - case uint: - return x / int(y) - case uint8: - return x / int(y) - case uint16: - return x / int(y) - case uint32: - return x / int(y) - case uint64: - return x / int(y) - case int: - return x / y - case int8: - return int8(x) / y - case int16: - return int16(x) / y - case int32: - return int32(x) / y - case int64: - return int64(x) / y - case float32: - return float32(x) / y - case float64: - return float64(x) / y - } - case int8: - switch y := b.(type) { - case uint: - return x / int8(y) - case uint8: - return x / int8(y) - case uint16: - return x / int8(y) - case uint32: - return x / int8(y) - case uint64: - return x / int8(y) - case int: - return x / int8(y) - case int8: - return x / y - case int16: - return int16(x) / y - case int32: - return int32(x) / y - case int64: - return int64(x) / y - case float32: - return float32(x) / y - case float64: - return float64(x) / y - } - case int16: - switch y := b.(type) { - case uint: - return x / int16(y) - case uint8: - return x / int16(y) - case uint16: - return x / int16(y) - case uint32: - return x / int16(y) - case uint64: - return x / int16(y) - case int: - return x / int16(y) - case int8: - return x / int16(y) - case int16: - return x / y - case int32: - return int32(x) / y - case int64: - return int64(x) / y - case float32: - return float32(x) / y - case float64: - return float64(x) / y - } - case int32: - switch y := b.(type) { - case uint: - return x / int32(y) - case uint8: - return x / int32(y) - case uint16: - return x / int32(y) - case uint32: - return x / int32(y) - case uint64: - return x / int32(y) - case int: - return x / int32(y) - case int8: - return x / int32(y) - case int16: - return x / int32(y) - case int32: - return x / y - case int64: - return int64(x) / y - case float32: - return float32(x) / y - case float64: - return float64(x) / y - } - case int64: - switch y := b.(type) { - case uint: - return x / int64(y) - case uint8: - return x / int64(y) - case uint16: - return x / int64(y) - case uint32: - return x / int64(y) - case uint64: - return x / int64(y) - case int: - return x / int64(y) - case int8: - return x / int64(y) - case int16: - return x / int64(y) - case int32: - return x / int64(y) - case int64: - return x / y - case float32: - return float32(x) / y - case float64: - return float64(x) / y - } - case float32: - switch y := b.(type) { - case uint: - return x / float32(y) - case uint8: - return x / float32(y) - case uint16: - return x / float32(y) - case uint32: - return x / float32(y) - case uint64: - return x / float32(y) - case int: - return x / float32(y) - case int8: - return x / float32(y) - case int16: - return x / float32(y) - case int32: - return x / float32(y) - case int64: - return x / float32(y) - case float32: - return x / y - case float64: - return float64(x) / y - } - case float64: - switch y := b.(type) { - case uint: - return x / float64(y) - case uint8: - return x / float64(y) - case uint16: - return x / float64(y) - case uint32: - return x / float64(y) - case uint64: - return x / float64(y) - case int: - return x / float64(y) - case int8: - return x / float64(y) - case int16: - return x / float64(y) - case int32: - return x / float64(y) - case int64: - return x / float64(y) - case float32: - return x / float64(y) - case float64: - return x / y - } - } - panic(fmt.Sprintf("invalid operation: %T %v %T", a, "/", b)) -} - -func modulo(a, b interface{}) interface{} { - switch x := a.(type) { - case uint: - switch y := b.(type) { - case uint: - return x % y - case uint8: - return uint8(x) % y - case uint16: - return uint16(x) % y - case uint32: - return uint32(x) % y - case uint64: - return uint64(x) % y - case int: - return int(x) % y - case int8: - return int8(x) % y - case int16: - return int16(x) % y - case int32: - return int32(x) % y - case int64: - return int64(x) % y - } - case uint8: - switch y := b.(type) { - case uint: - return x % uint8(y) - case uint8: - return x % y - case uint16: - return uint16(x) % y - case uint32: - return uint32(x) % y - case uint64: - return uint64(x) % y - case int: - return int(x) % y - case int8: - return int8(x) % y - case int16: - return int16(x) % y - case int32: - return int32(x) % y - case int64: - return int64(x) % y - } - case uint16: - switch y := b.(type) { - case uint: - return x % uint16(y) - case uint8: - return x % uint16(y) - case uint16: - return x % y - case uint32: - return uint32(x) % y - case uint64: - return uint64(x) % y - case int: - return int(x) % y - case int8: - return int8(x) % y - case int16: - return int16(x) % y - case int32: - return int32(x) % y - case int64: - return int64(x) % y - } - case uint32: - switch y := b.(type) { - case uint: - return x % uint32(y) - case uint8: - return x % uint32(y) - case uint16: - return x % uint32(y) - case uint32: - return x % y - case uint64: - return uint64(x) % y - case int: - return int(x) % y - case int8: - return int8(x) % y - case int16: - return int16(x) % y - case int32: - return int32(x) % y - case int64: - return int64(x) % y - } - case uint64: - switch y := b.(type) { - case uint: - return x % uint64(y) - case uint8: - return x % uint64(y) - case uint16: - return x % uint64(y) - case uint32: - return x % uint64(y) - case uint64: - return x % y - case int: - return int(x) % y - case int8: - return int8(x) % y - case int16: - return int16(x) % y - case int32: - return int32(x) % y - case int64: - return int64(x) % y - } - case int: - switch y := b.(type) { - case uint: - return x % int(y) - case uint8: - return x % int(y) - case uint16: - return x % int(y) - case uint32: - return x % int(y) - case uint64: - return x % int(y) - case int: - return x % y - case int8: - return int8(x) % y - case int16: - return int16(x) % y - case int32: - return int32(x) % y - case int64: - return int64(x) % y - } - case int8: - switch y := b.(type) { - case uint: - return x % int8(y) - case uint8: - return x % int8(y) - case uint16: - return x % int8(y) - case uint32: - return x % int8(y) - case uint64: - return x % int8(y) - case int: - return x % int8(y) - case int8: - return x % y - case int16: - return int16(x) % y - case int32: - return int32(x) % y - case int64: - return int64(x) % y - } - case int16: - switch y := b.(type) { - case uint: - return x % int16(y) - case uint8: - return x % int16(y) - case uint16: - return x % int16(y) - case uint32: - return x % int16(y) - case uint64: - return x % int16(y) - case int: - return x % int16(y) - case int8: - return x % int16(y) - case int16: - return x % y - case int32: - return int32(x) % y - case int64: - return int64(x) % y - } - case int32: - switch y := b.(type) { - case uint: - return x % int32(y) - case uint8: - return x % int32(y) - case uint16: - return x % int32(y) - case uint32: - return x % int32(y) - case uint64: - return x % int32(y) - case int: - return x % int32(y) - case int8: - return x % int32(y) - case int16: - return x % int32(y) - case int32: - return x % y - case int64: - return int64(x) % y - } - case int64: - switch y := b.(type) { - case uint: - return x % int64(y) - case uint8: - return x % int64(y) - case uint16: - return x % int64(y) - case uint32: - return x % int64(y) - case uint64: - return x % int64(y) - case int: - return x % int64(y) - case int8: - return x % int64(y) - case int16: - return x % int64(y) - case int32: - return x % int64(y) - case int64: - return x % y - } - } - panic(fmt.Sprintf("invalid operation: %T %v %T", a, "%", b)) -} diff --git a/vendor/github.com/antonmedv/expr/vm/opcodes.go b/vendor/github.com/antonmedv/expr/vm/opcodes.go deleted file mode 100644 index 7f2dd37..0000000 --- a/vendor/github.com/antonmedv/expr/vm/opcodes.go +++ /dev/null @@ -1,56 +0,0 @@ -package vm - -const ( - OpPush byte = iota - OpPop - OpRot - OpFetch - OpFetchNilSafe - OpFetchMap - OpTrue - OpFalse - OpNil - OpNegate - OpNot - OpEqual - OpEqualInt - OpEqualString - OpJump - OpJumpIfTrue - OpJumpIfFalse - OpJumpBackward - OpIn - OpLess - OpMore - OpLessOrEqual - OpMoreOrEqual - OpAdd - OpSubtract - OpMultiply - OpDivide - OpModulo - OpExponent - OpRange - OpMatches - OpMatchesConst - OpContains - OpStartsWith - OpEndsWith - OpIndex - OpSlice - OpProperty - OpPropertyNilSafe - OpCall - OpCallFast - OpMethod - OpMethodNilSafe - OpArray - OpMap - OpLen - OpCast - OpStore - OpLoad - OpInc - OpBegin - OpEnd // This opcode must be at the end of this list. -) diff --git a/vendor/github.com/antonmedv/expr/vm/program.go b/vendor/github.com/antonmedv/expr/vm/program.go deleted file mode 100644 index 5a41f8a..0000000 --- a/vendor/github.com/antonmedv/expr/vm/program.go +++ /dev/null @@ -1,225 +0,0 @@ -package vm - -import ( - "encoding/binary" - "fmt" - "regexp" - - "github.com/antonmedv/expr/file" -) - -type Program struct { - Source *file.Source - Locations map[int]file.Location - Constants []interface{} - Bytecode []byte -} - -func (program *Program) Disassemble() string { - out := "" - ip := 0 - for ip < len(program.Bytecode) { - pp := ip - op := program.Bytecode[ip] - ip++ - - readArg := func() uint16 { - if ip+1 >= len(program.Bytecode) { - return 0 - } - - i := binary.LittleEndian.Uint16([]byte{program.Bytecode[ip], program.Bytecode[ip+1]}) - ip += 2 - return i - } - - code := func(label string) { - out += fmt.Sprintf("%v\t%v\n", pp, label) - } - jump := func(label string) { - a := readArg() - out += fmt.Sprintf("%v\t%v\t%v\t(%v)\n", pp, label, a, ip+int(a)) - } - back := func(label string) { - a := readArg() - out += fmt.Sprintf("%v\t%v\t%v\t(%v)\n", pp, label, a, ip-int(a)) - } - argument := func(label string) { - a := readArg() - out += fmt.Sprintf("%v\t%v\t%v\n", pp, label, a) - } - constant := func(label string) { - a := readArg() - var c interface{} - if int(a) < len(program.Constants) { - c = program.Constants[a] - } - if r, ok := c.(*regexp.Regexp); ok { - c = r.String() - } - out += fmt.Sprintf("%v\t%v\t%v\t%#v\n", pp, label, a, c) - } - - switch op { - case OpPush: - constant("OpPush") - - case OpPop: - code("OpPop") - - case OpRot: - code("OpRot") - - case OpFetch: - constant("OpFetch") - - case OpFetchNilSafe: - constant("OpFetchNilSafe") - - case OpFetchMap: - constant("OpFetchMap") - - case OpTrue: - code("OpTrue") - - case OpFalse: - code("OpFalse") - - case OpNil: - code("OpNil") - - case OpNegate: - code("OpNegate") - - case OpNot: - code("OpNot") - - case OpEqual: - code("OpEqual") - - case OpEqualInt: - code("OpEqualInt") - - case OpEqualString: - code("OpEqualString") - - case OpJump: - jump("OpJump") - - case OpJumpIfTrue: - jump("OpJumpIfTrue") - - case OpJumpIfFalse: - jump("OpJumpIfFalse") - - case OpJumpBackward: - back("OpJumpBackward") - - case OpIn: - code("OpIn") - - case OpLess: - code("OpLess") - - case OpMore: - code("OpMore") - - case OpLessOrEqual: - code("OpLessOrEqual") - - case OpMoreOrEqual: - code("OpMoreOrEqual") - - case OpAdd: - code("OpAdd") - - case OpSubtract: - code("OpSubtract") - - case OpMultiply: - code("OpMultiply") - - case OpDivide: - code("OpDivide") - - case OpModulo: - code("OpModulo") - - case OpExponent: - code("OpExponent") - - case OpRange: - code("OpRange") - - case OpMatches: - code("OpMatches") - - case OpMatchesConst: - constant("OpMatchesConst") - - case OpContains: - code("OpContains") - - case OpStartsWith: - code("OpStartsWith") - - case OpEndsWith: - code("OpEndsWith") - - case OpIndex: - code("OpIndex") - - case OpSlice: - code("OpSlice") - - case OpProperty: - constant("OpProperty") - - case OpPropertyNilSafe: - constant("OpPropertyNilSafe") - - case OpCall: - constant("OpCall") - - case OpCallFast: - constant("OpCallFast") - - case OpMethod: - constant("OpMethod") - - case OpMethodNilSafe: - constant("OpMethodNilSafe") - - case OpArray: - code("OpArray") - - case OpMap: - code("OpMap") - - case OpLen: - code("OpLen") - - case OpCast: - argument("OpCast") - - case OpStore: - constant("OpStore") - - case OpLoad: - constant("OpLoad") - - case OpInc: - constant("OpInc") - - case OpBegin: - code("OpBegin") - - case OpEnd: - code("OpEnd") - - default: - out += fmt.Sprintf("%v\t%#x\n", pp, op) - } - } - return out -} diff --git a/vendor/github.com/antonmedv/expr/vm/runtime.go b/vendor/github.com/antonmedv/expr/vm/runtime.go deleted file mode 100644 index 2e00913..0000000 --- a/vendor/github.com/antonmedv/expr/vm/runtime.go +++ /dev/null @@ -1,370 +0,0 @@ -package vm - -//go:generate go run ./generate - -import ( - "fmt" - "math" - "reflect" -) - -type Call struct { - Name string - Size int -} - -type Scope map[string]interface{} - -type Fetcher interface { - Fetch(interface{}) interface{} -} - -func fetch(from, i interface{}, nilsafe bool) interface{} { - if fetcher, ok := from.(Fetcher); ok { - value := fetcher.Fetch(i) - if value != nil { - return value - } - if !nilsafe { - panic(fmt.Sprintf("cannot fetch %v from %T", i, from)) - } - return nil - } - - v := reflect.ValueOf(from) - kind := v.Kind() - - // Structures can be access through a pointer or through a value, when they - // are accessed through a pointer we don't want to copy them to a value. - if kind == reflect.Ptr && reflect.Indirect(v).Kind() == reflect.Struct { - v = reflect.Indirect(v) - kind = v.Kind() - } - - switch kind { - - case reflect.Array, reflect.Slice, reflect.String: - value := v.Index(toInt(i)) - if value.IsValid() && value.CanInterface() { - return value.Interface() - } - - case reflect.Map: - value := v.MapIndex(reflect.ValueOf(i)) - if value.IsValid() { - if value.CanInterface() { - return value.Interface() - } - } else { - elem := reflect.TypeOf(from).Elem() - return reflect.Zero(elem).Interface() - } - - case reflect.Struct: - value := v.FieldByName(reflect.ValueOf(i).String()) - if value.IsValid() && value.CanInterface() { - return value.Interface() - } - } - if !nilsafe { - panic(fmt.Sprintf("cannot fetch %v from %T", i, from)) - } - return nil -} - -func slice(array, from, to interface{}) interface{} { - v := reflect.ValueOf(array) - - switch v.Kind() { - case reflect.Array, reflect.Slice, reflect.String: - length := v.Len() - a, b := toInt(from), toInt(to) - - if b > length { - b = length - } - if a > b { - a = b - } - - value := v.Slice(a, b) - if value.IsValid() && value.CanInterface() { - return value.Interface() - } - - case reflect.Ptr: - value := v.Elem() - if value.IsValid() && value.CanInterface() { - return slice(value.Interface(), from, to) - } - - } - panic(fmt.Sprintf("cannot slice %v", from)) -} - -func FetchFn(from interface{}, name string) reflect.Value { - v := reflect.ValueOf(from) - - // Methods can be defined on any type. - if v.NumMethod() > 0 { - method := v.MethodByName(name) - if method.IsValid() { - return method - } - } - - d := v - if v.Kind() == reflect.Ptr { - d = v.Elem() - } - - switch d.Kind() { - case reflect.Map: - value := d.MapIndex(reflect.ValueOf(name)) - if value.IsValid() && value.CanInterface() { - return value.Elem() - } - case reflect.Struct: - // If struct has not method, maybe it has func field. - // To access this field we need dereference value. - value := d.FieldByName(name) - if value.IsValid() { - return value - } - } - panic(fmt.Sprintf(`cannot get "%v" from %T`, name, from)) -} - -func FetchFnNil(from interface{}, name string) reflect.Value { - if v := reflect.ValueOf(from); !v.IsValid() { - return v - } - return FetchFn(from, name) -} - -func in(needle interface{}, array interface{}) bool { - if array == nil { - return false - } - v := reflect.ValueOf(array) - - switch v.Kind() { - - case reflect.Array, reflect.Slice: - for i := 0; i < v.Len(); i++ { - value := v.Index(i) - if value.IsValid() && value.CanInterface() { - if equal(value.Interface(), needle).(bool) { - return true - } - } - } - return false - - case reflect.Map: - n := reflect.ValueOf(needle) - if !n.IsValid() { - panic(fmt.Sprintf("cannot use %T as index to %T", needle, array)) - } - value := v.MapIndex(n) - if value.IsValid() { - return true - } - return false - - case reflect.Struct: - n := reflect.ValueOf(needle) - if !n.IsValid() || n.Kind() != reflect.String { - panic(fmt.Sprintf("cannot use %T as field name of %T", needle, array)) - } - value := v.FieldByName(n.String()) - if value.IsValid() { - return true - } - return false - - case reflect.Ptr: - value := v.Elem() - if value.IsValid() && value.CanInterface() { - return in(needle, value.Interface()) - } - return false - } - - panic(fmt.Sprintf(`operator "in"" not defined on %T`, array)) -} - -func length(a interface{}) int { - v := reflect.ValueOf(a) - switch v.Kind() { - case reflect.Array, reflect.Slice, reflect.Map, reflect.String: - return v.Len() - default: - panic(fmt.Sprintf("invalid argument for len (type %T)", a)) - } -} - -func negate(i interface{}) interface{} { - switch v := i.(type) { - case float32: - return -v - case float64: - return -v - - case int: - return -v - case int8: - return -v - case int16: - return -v - case int32: - return -v - case int64: - return -v - - case uint: - return -v - case uint8: - return -v - case uint16: - return -v - case uint32: - return -v - case uint64: - return -v - - default: - panic(fmt.Sprintf("invalid operation: - %T", v)) - } -} - -func exponent(a, b interface{}) float64 { - return math.Pow(toFloat64(a), toFloat64(b)) -} - -func makeRange(min, max int) []int { - size := max - min + 1 - if size <= 0 { - return []int{} - } - rng := make([]int, size) - for i := range rng { - rng[i] = min + i - } - return rng -} - -func toInt(a interface{}) int { - switch x := a.(type) { - case float32: - return int(x) - case float64: - return int(x) - - case int: - return x - case int8: - return int(x) - case int16: - return int(x) - case int32: - return int(x) - case int64: - return int(x) - - case uint: - return int(x) - case uint8: - return int(x) - case uint16: - return int(x) - case uint32: - return int(x) - case uint64: - return int(x) - - default: - panic(fmt.Sprintf("invalid operation: int(%T)", x)) - } -} - -func toInt64(a interface{}) int64 { - switch x := a.(type) { - case float32: - return int64(x) - case float64: - return int64(x) - - case int: - return int64(x) - case int8: - return int64(x) - case int16: - return int64(x) - case int32: - return int64(x) - case int64: - return x - - case uint: - return int64(x) - case uint8: - return int64(x) - case uint16: - return int64(x) - case uint32: - return int64(x) - case uint64: - return int64(x) - - default: - panic(fmt.Sprintf("invalid operation: int64(%T)", x)) - } -} - -func toFloat64(a interface{}) float64 { - switch x := a.(type) { - case float32: - return float64(x) - case float64: - return x - - case int: - return float64(x) - case int8: - return float64(x) - case int16: - return float64(x) - case int32: - return float64(x) - case int64: - return float64(x) - - case uint: - return float64(x) - case uint8: - return float64(x) - case uint16: - return float64(x) - case uint32: - return float64(x) - case uint64: - return float64(x) - - default: - panic(fmt.Sprintf("invalid operation: float64(%T)", x)) - } -} - -func isNil(v interface{}) bool { - if v == nil { - return true - } - r := reflect.ValueOf(v) - switch r.Kind() { - case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice: - return r.IsNil() - default: - return false - } -} diff --git a/vendor/github.com/antonmedv/expr/vm/vm.go b/vendor/github.com/antonmedv/expr/vm/vm.go deleted file mode 100644 index 6957dfa..0000000 --- a/vendor/github.com/antonmedv/expr/vm/vm.go +++ /dev/null @@ -1,484 +0,0 @@ -package vm - -import ( - "fmt" - "reflect" - "regexp" - "strings" - - "github.com/antonmedv/expr/file" -) - -var errorType = reflect.TypeOf((*error)(nil)).Elem() - -var ( - MemoryBudget int = 1e6 -) - -func Run(program *Program, env interface{}) (interface{}, error) { - if program == nil { - return nil, fmt.Errorf("program is nil") - } - - vm := VM{} - return vm.Run(program, env) -} - -type VM struct { - stack []interface{} - constants []interface{} - bytecode []byte - ip int - pp int - scopes []Scope - debug bool - step chan struct{} - curr chan int - memory int - limit int -} - -func Debug() *VM { - vm := &VM{ - debug: true, - step: make(chan struct{}, 0), - curr: make(chan int, 0), - } - return vm -} - -func (vm *VM) Run(program *Program, env interface{}) (out interface{}, err error) { - defer func() { - if r := recover(); r != nil { - f := &file.Error{ - Location: program.Locations[vm.pp], - Message: fmt.Sprintf("%v", r), - } - err = f.Bind(program.Source) - } - }() - - vm.limit = MemoryBudget - vm.ip = 0 - vm.pp = 0 - - if vm.stack == nil { - vm.stack = make([]interface{}, 0, 2) - } else { - vm.stack = vm.stack[0:0] - } - - if vm.scopes != nil { - vm.scopes = vm.scopes[0:0] - } - - vm.bytecode = program.Bytecode - vm.constants = program.Constants - - for vm.ip < len(vm.bytecode) { - - if vm.debug { - <-vm.step - } - - vm.pp = vm.ip - vm.ip++ - op := vm.bytecode[vm.pp] - - switch op { - - case OpPush: - vm.push(vm.constant()) - - case OpPop: - vm.pop() - - case OpRot: - b := vm.pop() - a := vm.pop() - vm.push(b) - vm.push(a) - - case OpFetch: - vm.push(fetch(env, vm.constant(), false)) - - case OpFetchNilSafe: - vm.push(fetch(env, vm.constant(), true)) - - case OpFetchMap: - vm.push(env.(map[string]interface{})[vm.constant().(string)]) - - case OpTrue: - vm.push(true) - - case OpFalse: - vm.push(false) - - case OpNil: - vm.push(nil) - - case OpNegate: - v := negate(vm.pop()) - vm.push(v) - - case OpNot: - v := vm.pop().(bool) - vm.push(!v) - - case OpEqual: - b := vm.pop() - a := vm.pop() - vm.push(equal(a, b)) - - case OpEqualInt: - b := vm.pop() - a := vm.pop() - vm.push(a.(int) == b.(int)) - - case OpEqualString: - b := vm.pop() - a := vm.pop() - vm.push(a.(string) == b.(string)) - - case OpJump: - offset := vm.arg() - vm.ip += int(offset) - - case OpJumpIfTrue: - offset := vm.arg() - if vm.current().(bool) { - vm.ip += int(offset) - } - - case OpJumpIfFalse: - offset := vm.arg() - if !vm.current().(bool) { - vm.ip += int(offset) - } - - case OpJumpBackward: - offset := vm.arg() - vm.ip -= int(offset) - - case OpIn: - b := vm.pop() - a := vm.pop() - vm.push(in(a, b)) - - case OpLess: - b := vm.pop() - a := vm.pop() - vm.push(less(a, b)) - - case OpMore: - b := vm.pop() - a := vm.pop() - vm.push(more(a, b)) - - case OpLessOrEqual: - b := vm.pop() - a := vm.pop() - vm.push(lessOrEqual(a, b)) - - case OpMoreOrEqual: - b := vm.pop() - a := vm.pop() - vm.push(moreOrEqual(a, b)) - - case OpAdd: - b := vm.pop() - a := vm.pop() - vm.push(add(a, b)) - - case OpSubtract: - b := vm.pop() - a := vm.pop() - vm.push(subtract(a, b)) - - case OpMultiply: - b := vm.pop() - a := vm.pop() - vm.push(multiply(a, b)) - - case OpDivide: - b := vm.pop() - a := vm.pop() - vm.push(divide(a, b)) - - case OpModulo: - b := vm.pop() - a := vm.pop() - vm.push(modulo(a, b)) - - case OpExponent: - b := vm.pop() - a := vm.pop() - vm.push(exponent(a, b)) - - case OpRange: - b := vm.pop() - a := vm.pop() - min := toInt(a) - max := toInt(b) - size := max - min + 1 - if vm.memory+size >= vm.limit { - panic("memory budget exceeded") - } - vm.push(makeRange(min, max)) - vm.memory += size - - case OpMatches: - b := vm.pop() - a := vm.pop() - match, err := regexp.MatchString(b.(string), a.(string)) - if err != nil { - panic(err) - } - - vm.push(match) - - case OpMatchesConst: - a := vm.pop() - r := vm.constant().(*regexp.Regexp) - vm.push(r.MatchString(a.(string))) - - case OpContains: - b := vm.pop() - a := vm.pop() - vm.push(strings.Contains(a.(string), b.(string))) - - case OpStartsWith: - b := vm.pop() - a := vm.pop() - vm.push(strings.HasPrefix(a.(string), b.(string))) - - case OpEndsWith: - b := vm.pop() - a := vm.pop() - vm.push(strings.HasSuffix(a.(string), b.(string))) - - case OpIndex: - b := vm.pop() - a := vm.pop() - vm.push(fetch(a, b, false)) - - case OpSlice: - from := vm.pop() - to := vm.pop() - node := vm.pop() - vm.push(slice(node, from, to)) - - case OpProperty: - a := vm.pop() - b := vm.constant() - vm.push(fetch(a, b, false)) - - case OpPropertyNilSafe: - a := vm.pop() - b := vm.constant() - vm.push(fetch(a, b, true)) - - case OpCall: - call := vm.constant().(Call) - in := make([]reflect.Value, call.Size) - for i := call.Size - 1; i >= 0; i-- { - param := vm.pop() - if param == nil && reflect.TypeOf(param) == nil { - // In case of nil value and nil type use this hack, - // otherwise reflect.Call will panic on zero value. - in[i] = reflect.ValueOf(¶m).Elem() - } else { - in[i] = reflect.ValueOf(param) - } - } - out := FetchFn(env, call.Name).Call(in) - if len(out) == 2 && out[1].Type() == errorType && !out[1].IsNil() { - return nil, out[1].Interface().(error) - } - vm.push(out[0].Interface()) - - case OpCallFast: - call := vm.constant().(Call) - in := make([]interface{}, call.Size) - for i := call.Size - 1; i >= 0; i-- { - in[i] = vm.pop() - } - fn := FetchFn(env, call.Name).Interface() - if typed, ok := fn.(func(...interface{}) interface{}); ok { - vm.push(typed(in...)) - } else if typed, ok := fn.(func(...interface{}) (interface{}, error)); ok { - res, err := typed(in...) - if err != nil { - return nil, err - } - vm.push(res) - } - - case OpMethod: - call := vm.constants[vm.arg()].(Call) - in := make([]reflect.Value, call.Size) - for i := call.Size - 1; i >= 0; i-- { - param := vm.pop() - if param == nil && reflect.TypeOf(param) == nil { - // In case of nil value and nil type use this hack, - // otherwise reflect.Call will panic on zero value. - in[i] = reflect.ValueOf(¶m).Elem() - } else { - in[i] = reflect.ValueOf(param) - } - } - out := FetchFn(vm.pop(), call.Name).Call(in) - if len(out) == 2 && out[1].Type() == errorType && !out[1].IsNil() { - return nil, out[1].Interface().(error) - } - vm.push(out[0].Interface()) - - case OpMethodNilSafe: - call := vm.constants[vm.arg()].(Call) - in := make([]reflect.Value, call.Size) - for i := call.Size - 1; i >= 0; i-- { - param := vm.pop() - if param == nil && reflect.TypeOf(param) == nil { - // In case of nil value and nil type use this hack, - // otherwise reflect.Call will panic on zero value. - in[i] = reflect.ValueOf(¶m).Elem() - } else { - in[i] = reflect.ValueOf(param) - } - } - fn := FetchFnNil(vm.pop(), call.Name) - if !fn.IsValid() { - vm.push(nil) - } else { - out := fn.Call(in) - vm.push(out[0].Interface()) - } - - case OpArray: - size := vm.pop().(int) - array := make([]interface{}, size) - for i := size - 1; i >= 0; i-- { - array[i] = vm.pop() - } - vm.push(array) - vm.memory += size - if vm.memory >= vm.limit { - panic("memory budget exceeded") - } - - case OpMap: - size := vm.pop().(int) - m := make(map[string]interface{}) - for i := size - 1; i >= 0; i-- { - value := vm.pop() - key := vm.pop() - m[key.(string)] = value - } - vm.push(m) - vm.memory += size - if vm.memory >= vm.limit { - panic("memory budget exceeded") - } - - case OpLen: - vm.push(length(vm.current())) - - case OpCast: - t := vm.arg() - switch t { - case 0: - vm.push(toInt64(vm.pop())) - case 1: - vm.push(toFloat64(vm.pop())) - } - - case OpStore: - scope := vm.Scope() - key := vm.constant().(string) - value := vm.pop() - scope[key] = value - - case OpLoad: - scope := vm.Scope() - key := vm.constant().(string) - vm.push(scope[key]) - - case OpInc: - scope := vm.Scope() - key := vm.constant().(string) - i := scope[key].(int) - i++ - scope[key] = i - - case OpBegin: - scope := make(Scope) - vm.scopes = append(vm.scopes, scope) - - case OpEnd: - vm.scopes = vm.scopes[:len(vm.scopes)-1] - - default: - panic(fmt.Sprintf("unknown bytecode %#x", op)) - } - - if vm.debug { - vm.curr <- vm.ip - } - } - - if vm.debug { - close(vm.curr) - close(vm.step) - } - - if len(vm.stack) > 0 { - return vm.pop(), nil - } - - return nil, nil -} - -func (vm *VM) push(value interface{}) { - vm.stack = append(vm.stack, value) -} - -func (vm *VM) current() interface{} { - return vm.stack[len(vm.stack)-1] -} - -func (vm *VM) pop() interface{} { - value := vm.stack[len(vm.stack)-1] - vm.stack = vm.stack[:len(vm.stack)-1] - return value -} - -func (vm *VM) arg() uint16 { - b0, b1 := vm.bytecode[vm.ip], vm.bytecode[vm.ip+1] - vm.ip += 2 - return uint16(b0) | uint16(b1)<<8 -} - -func (vm *VM) constant() interface{} { - return vm.constants[vm.arg()] -} - -func (vm *VM) Stack() []interface{} { - return vm.stack -} - -func (vm *VM) Scope() Scope { - if len(vm.scopes) > 0 { - return vm.scopes[len(vm.scopes)-1] - } - return nil -} - -func (vm *VM) Step() { - if vm.ip < len(vm.bytecode) { - vm.step <- struct{}{} - } -} - -func (vm *VM) Position() chan int { - return vm.curr -} diff --git a/vendor/github.com/aymerick/douceur/LICENSE b/vendor/github.com/aymerick/douceur/LICENSE deleted file mode 100644 index 6ce87cd..0000000 --- a/vendor/github.com/aymerick/douceur/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Aymerick JEHANNE - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/vendor/github.com/aymerick/douceur/css/declaration.go b/vendor/github.com/aymerick/douceur/css/declaration.go deleted file mode 100644 index 61d29d3..0000000 --- a/vendor/github.com/aymerick/douceur/css/declaration.go +++ /dev/null @@ -1,60 +0,0 @@ -package css - -import "fmt" - -// Declaration represents a parsed style property -type Declaration struct { - Property string - Value string - Important bool -} - -// NewDeclaration instanciates a new Declaration -func NewDeclaration() *Declaration { - return &Declaration{} -} - -// Returns string representation of the Declaration -func (decl *Declaration) String() string { - return decl.StringWithImportant(true) -} - -// StringWithImportant returns string representation with optional !important part -func (decl *Declaration) StringWithImportant(option bool) string { - result := fmt.Sprintf("%s: %s", decl.Property, decl.Value) - - if option && decl.Important { - result += " !important" - } - - result += ";" - - return result -} - -// Equal returns true if both Declarations are equals -func (decl *Declaration) Equal(other *Declaration) bool { - return (decl.Property == other.Property) && (decl.Value == other.Value) && (decl.Important == other.Important) -} - -// -// DeclarationsByProperty -// - -// DeclarationsByProperty represents sortable style declarations -type DeclarationsByProperty []*Declaration - -// Implements sort.Interface -func (declarations DeclarationsByProperty) Len() int { - return len(declarations) -} - -// Implements sort.Interface -func (declarations DeclarationsByProperty) Swap(i, j int) { - declarations[i], declarations[j] = declarations[j], declarations[i] -} - -// Implements sort.Interface -func (declarations DeclarationsByProperty) Less(i, j int) bool { - return declarations[i].Property < declarations[j].Property -} diff --git a/vendor/github.com/aymerick/douceur/css/rule.go b/vendor/github.com/aymerick/douceur/css/rule.go deleted file mode 100644 index b5a44b5..0000000 --- a/vendor/github.com/aymerick/douceur/css/rule.go +++ /dev/null @@ -1,230 +0,0 @@ -package css - -import ( - "fmt" - "strings" -) - -const ( - indentSpace = 2 -) - -// RuleKind represents a Rule kind -type RuleKind int - -// Rule kinds -const ( - QualifiedRule RuleKind = iota - AtRule -) - -// At Rules than have Rules inside their block instead of Declarations -var atRulesWithRulesBlock = []string{ - "@document", "@font-feature-values", "@keyframes", "@media", "@supports", -} - -// Rule represents a parsed CSS rule -type Rule struct { - Kind RuleKind - - // At Rule name (eg: "@media") - Name string - - // Raw prelude - Prelude string - - // Qualified Rule selectors parsed from prelude - Selectors []string - - // Style properties - Declarations []*Declaration - - // At Rule embedded rules - Rules []*Rule - - // Current rule embedding level - EmbedLevel int -} - -// NewRule instanciates a new Rule -func NewRule(kind RuleKind) *Rule { - return &Rule{ - Kind: kind, - } -} - -// Returns string representation of rule kind -func (kind RuleKind) String() string { - switch kind { - case QualifiedRule: - return "Qualified Rule" - case AtRule: - return "At Rule" - default: - return "WAT" - } -} - -// EmbedsRules returns true if this rule embeds another rules -func (rule *Rule) EmbedsRules() bool { - if rule.Kind == AtRule { - for _, atRuleName := range atRulesWithRulesBlock { - if rule.Name == atRuleName { - return true - } - } - } - - return false -} - -// Equal returns true if both rules are equals -func (rule *Rule) Equal(other *Rule) bool { - if (rule.Kind != other.Kind) || - (rule.Prelude != other.Prelude) || - (rule.Name != other.Name) { - return false - } - - if (len(rule.Selectors) != len(other.Selectors)) || - (len(rule.Declarations) != len(other.Declarations)) || - (len(rule.Rules) != len(other.Rules)) { - return false - } - - for i, sel := range rule.Selectors { - if sel != other.Selectors[i] { - return false - } - } - - for i, decl := range rule.Declarations { - if !decl.Equal(other.Declarations[i]) { - return false - } - } - - for i, rule := range rule.Rules { - if !rule.Equal(other.Rules[i]) { - return false - } - } - - return true -} - -// Diff returns a string representation of rules differences -func (rule *Rule) Diff(other *Rule) []string { - result := []string{} - - if rule.Kind != other.Kind { - result = append(result, fmt.Sprintf("Kind: %s | %s", rule.Kind.String(), other.Kind.String())) - } - - if rule.Prelude != other.Prelude { - result = append(result, fmt.Sprintf("Prelude: \"%s\" | \"%s\"", rule.Prelude, other.Prelude)) - } - - if rule.Name != other.Name { - result = append(result, fmt.Sprintf("Name: \"%s\" | \"%s\"", rule.Name, other.Name)) - } - - if len(rule.Selectors) != len(other.Selectors) { - result = append(result, fmt.Sprintf("Selectors: %v | %v", strings.Join(rule.Selectors, ", "), strings.Join(other.Selectors, ", "))) - } else { - for i, sel := range rule.Selectors { - if sel != other.Selectors[i] { - result = append(result, fmt.Sprintf("Selector: \"%s\" | \"%s\"", sel, other.Selectors[i])) - } - } - } - - if len(rule.Declarations) != len(other.Declarations) { - result = append(result, fmt.Sprintf("Declarations Nb: %d | %d", len(rule.Declarations), len(other.Declarations))) - } else { - for i, decl := range rule.Declarations { - if !decl.Equal(other.Declarations[i]) { - result = append(result, fmt.Sprintf("Declaration: \"%s\" | \"%s\"", decl.String(), other.Declarations[i].String())) - } - } - } - - if len(rule.Rules) != len(other.Rules) { - result = append(result, fmt.Sprintf("Rules Nb: %d | %d", len(rule.Rules), len(other.Rules))) - } else { - - for i, rule := range rule.Rules { - if !rule.Equal(other.Rules[i]) { - result = append(result, fmt.Sprintf("Rule: \"%s\" | \"%s\"", rule.String(), other.Rules[i].String())) - } - } - } - - return result -} - -// Returns the string representation of a rule -func (rule *Rule) String() string { - result := "" - - if rule.Kind == QualifiedRule { - for i, sel := range rule.Selectors { - if i != 0 { - result += ", " - } - result += sel - } - } else { - // AtRule - result += fmt.Sprintf("%s", rule.Name) - - if rule.Prelude != "" { - if result != "" { - result += " " - } - result += fmt.Sprintf("%s", rule.Prelude) - } - } - - if (len(rule.Declarations) == 0) && (len(rule.Rules) == 0) { - result += ";" - } else { - result += " {\n" - - if rule.EmbedsRules() { - for _, subRule := range rule.Rules { - result += fmt.Sprintf("%s%s\n", rule.indent(), subRule.String()) - } - } else { - for _, decl := range rule.Declarations { - result += fmt.Sprintf("%s%s\n", rule.indent(), decl.String()) - } - } - - result += fmt.Sprintf("%s}", rule.indentEndBlock()) - } - - return result -} - -// Returns identation spaces for declarations and rules -func (rule *Rule) indent() string { - result := "" - - for i := 0; i < ((rule.EmbedLevel + 1) * indentSpace); i++ { - result += " " - } - - return result -} - -// Returns identation spaces for end of block character -func (rule *Rule) indentEndBlock() string { - result := "" - - for i := 0; i < (rule.EmbedLevel * indentSpace); i++ { - result += " " - } - - return result -} diff --git a/vendor/github.com/aymerick/douceur/css/stylesheet.go b/vendor/github.com/aymerick/douceur/css/stylesheet.go deleted file mode 100644 index 6b32c2e..0000000 --- a/vendor/github.com/aymerick/douceur/css/stylesheet.go +++ /dev/null @@ -1,25 +0,0 @@ -package css - -// Stylesheet represents a parsed stylesheet -type Stylesheet struct { - Rules []*Rule -} - -// NewStylesheet instanciate a new Stylesheet -func NewStylesheet() *Stylesheet { - return &Stylesheet{} -} - -// Returns string representation of the Stylesheet -func (sheet *Stylesheet) String() string { - result := "" - - for _, rule := range sheet.Rules { - if result != "" { - result += "\n" - } - result += rule.String() - } - - return result -} diff --git a/vendor/github.com/aymerick/douceur/inliner/element.go b/vendor/github.com/aymerick/douceur/inliner/element.go deleted file mode 100644 index cd96a6f..0000000 --- a/vendor/github.com/aymerick/douceur/inliner/element.go +++ /dev/null @@ -1,181 +0,0 @@ -package inliner - -import ( - "sort" - - "github.com/PuerkitoBio/goquery" - - "github.com/aymerick/douceur/css" - "github.com/aymerick/douceur/parser" -) - -// Element represents a HTML element with matching CSS rules -type Element struct { - // The goquery handler - elt *goquery.Selection - - // The style rules to apply on that element - styleRules []*StyleRule -} - -// ElementAttr represents a HTML element attribute -type ElementAttr struct { - attr string - elements []string -} - -// Index is style property name -var styleToAttr map[string]*ElementAttr - -func init() { - // Borrowed from premailer: - // https://github.com/premailer/premailer/blob/master/lib/premailer/premailer.rb - styleToAttr = map[string]*ElementAttr{ - "text-align": { - "align", - []string{"h1", "h2", "h3", "h4", "h5", "h6", "p", "div", "blockquote", "tr", "th", "td"}, - }, - "background-color": { - "bgcolor", - []string{"body", "table", "tr", "th", "td"}, - }, - "background-image": { - "background", - []string{"table"}, - }, - "vertical-align": { - "valign", - []string{"th", "td"}, - }, - "float": { - "align", - []string{"img"}, - }, - // @todo width and height ? - } -} - -// NewElement instanciates a new element -func NewElement(elt *goquery.Selection) *Element { - return &Element{ - elt: elt, - } -} - -// Add a Style Rule to Element -func (element *Element) addStyleRule(styleRule *StyleRule) { - element.styleRules = append(element.styleRules, styleRule) -} - -// Inline styles on element -func (element *Element) inline() error { - // compute declarations - declarations, err := element.computeDeclarations() - if err != nil { - return err - } - - // set style attribute - styleValue := computeStyleValue(declarations) - if styleValue != "" { - element.elt.SetAttr("style", styleValue) - } - - // set additionnal attributes - element.setAttributesFromStyle(declarations) - - return nil -} - -// Compute css declarations -func (element *Element) computeDeclarations() ([]*css.Declaration, error) { - result := []*css.Declaration{} - - styles := make(map[string]*StyleDeclaration) - - // First: parsed stylesheets rules - mergeStyleDeclarations(element.styleRules, styles) - - // Then: inline rules - inlineRules, err := element.parseInlineStyle() - if err != nil { - return result, err - } - - mergeStyleDeclarations(inlineRules, styles) - - // map to array - for _, styleDecl := range styles { - result = append(result, styleDecl.Declaration) - } - - // sort declarations by property name - sort.Sort(css.DeclarationsByProperty(result)) - - return result, nil -} - -// Parse inline style rules -func (element *Element) parseInlineStyle() ([]*StyleRule, error) { - result := []*StyleRule{} - - styleValue, exists := element.elt.Attr("style") - if (styleValue == "") || !exists { - return result, nil - } - - declarations, err := parser.ParseDeclarations(styleValue) - if err != nil { - return result, err - } - - result = append(result, NewStyleRule(inlineFakeSelector, declarations)) - - return result, nil -} - -// Set additional attributes from style declarations -func (element *Element) setAttributesFromStyle(declarations []*css.Declaration) { - // for each style declarations - for _, declaration := range declarations { - if eltAttr := styleToAttr[declaration.Property]; eltAttr != nil { - // check if element is allowed for that attribute - for _, eltAllowed := range eltAttr.elements { - if element.elt.Nodes[0].Data == eltAllowed { - element.elt.SetAttr(eltAttr.attr, declaration.Value) - - break - } - } - } - } -} - -// helper -func computeStyleValue(declarations []*css.Declaration) string { - result := "" - - // set style attribute value - for _, declaration := range declarations { - if result != "" { - result += " " - } - - result += declaration.StringWithImportant(false) - } - - return result -} - -// helper -func mergeStyleDeclarations(styleRules []*StyleRule, output map[string]*StyleDeclaration) { - for _, styleRule := range styleRules { - for _, declaration := range styleRule.Declarations { - styleDecl := NewStyleDeclaration(styleRule, declaration) - - if (output[declaration.Property] == nil) || (styleDecl.Specificity() >= output[declaration.Property].Specificity()) { - output[declaration.Property] = styleDecl - } - } - } -} diff --git a/vendor/github.com/aymerick/douceur/inliner/inliner.go b/vendor/github.com/aymerick/douceur/inliner/inliner.go deleted file mode 100644 index 842a92d..0000000 --- a/vendor/github.com/aymerick/douceur/inliner/inliner.go +++ /dev/null @@ -1,243 +0,0 @@ -package inliner - -import ( - "fmt" - "strconv" - "strings" - - "github.com/PuerkitoBio/goquery" - "github.com/aymerick/douceur/css" - "github.com/aymerick/douceur/parser" - "golang.org/x/net/html" -) - -const ( - eltMarkerAttr = "douceur-mark" -) - -var unsupportedSelectors = []string{ - ":active", ":after", ":before", ":checked", ":disabled", ":enabled", - ":first-line", ":first-letter", ":focus", ":hover", ":invalid", ":in-range", - ":lang", ":link", ":root", ":selection", ":target", ":valid", ":visited"} - -// Inliner presents a CSS Inliner -type Inliner struct { - // Raw HTML - html string - - // Parsed HTML document - doc *goquery.Document - - // Parsed stylesheets - stylesheets []*css.Stylesheet - - // Collected inlinable style rules - rules []*StyleRule - - // HTML elements matching collected inlinable style rules - elements map[string]*Element - - // CSS rules that are not inlinable but that must be inserted in output document - rawRules []fmt.Stringer - - // current element marker value - eltMarker int -} - -// NewInliner instanciates a new Inliner -func NewInliner(html string) *Inliner { - return &Inliner{ - html: html, - elements: make(map[string]*Element), - } -} - -// Inline inlines css into html document -func Inline(html string) (string, error) { - result, err := NewInliner(html).Inline() - if err != nil { - return "", err - } - - return result, nil -} - -// Inline inlines CSS and returns HTML -func (inliner *Inliner) Inline() (string, error) { - // parse HTML document - if err := inliner.parseHTML(); err != nil { - return "", err - } - - // parse stylesheets - if err := inliner.parseStylesheets(); err != nil { - return "", err - } - - // collect elements and style rules - inliner.collectElementsAndRules() - - // inline css - if err := inliner.inlineStyleRules(); err != nil { - return "", err - } - - // insert raw stylesheet - inliner.insertRawStylesheet() - - // generate HTML document - return inliner.genHTML() -} - -// Parses raw html -func (inliner *Inliner) parseHTML() error { - doc, err := goquery.NewDocumentFromReader(strings.NewReader(inliner.html)) - if err != nil { - return err - } - - inliner.doc = doc - - return nil -} - -// Parses and removes stylesheets from HTML document -func (inliner *Inliner) parseStylesheets() error { - var result error - - inliner.doc.Find("style").EachWithBreak(func(i int, s *goquery.Selection) bool { - stylesheet, err := parser.Parse(s.Text()) - if err != nil { - result = err - return false - } - - inliner.stylesheets = append(inliner.stylesheets, stylesheet) - - // removes parsed stylesheet - s.Remove() - - return true - }) - - return result -} - -// Collects HTML elements matching parsed stylesheets, and thus collect used style rules -func (inliner *Inliner) collectElementsAndRules() { - for _, stylesheet := range inliner.stylesheets { - for _, rule := range stylesheet.Rules { - if rule.Kind == css.QualifiedRule { - // Let's go! - inliner.handleQualifiedRule(rule) - } else { - // Keep it 'as is' - inliner.rawRules = append(inliner.rawRules, rule) - } - } - } -} - -// Handles parsed qualified rule -func (inliner *Inliner) handleQualifiedRule(rule *css.Rule) { - for _, selector := range rule.Selectors { - if Inlinable(selector) { - inliner.doc.Find(selector).Each(func(i int, s *goquery.Selection) { - // get marker - eltMarker, exists := s.Attr(eltMarkerAttr) - if !exists { - // mark element - eltMarker = strconv.Itoa(inliner.eltMarker) - s.SetAttr(eltMarkerAttr, eltMarker) - inliner.eltMarker++ - - // add new element - inliner.elements[eltMarker] = NewElement(s) - } - - // add style rule for element - inliner.elements[eltMarker].addStyleRule(NewStyleRule(selector, rule.Declarations)) - }) - } else { - // Keep it 'as is' - inliner.rawRules = append(inliner.rawRules, NewStyleRule(selector, rule.Declarations)) - } - } -} - -// Inline style rules in HTML document -func (inliner *Inliner) inlineStyleRules() error { - for _, element := range inliner.elements { - // remove marker - element.elt.RemoveAttr(eltMarkerAttr) - - // inline element - err := element.inline() - if err != nil { - return err - } - } - - return nil -} - -// Computes raw CSS rules -func (inliner *Inliner) computeRawCSS() string { - result := "" - - for _, rawRule := range inliner.rawRules { - result += rawRule.String() - result += "\n" - } - - return result -} - -// Insert raw CSS rules into HTML document -func (inliner *Inliner) insertRawStylesheet() { - rawCSS := inliner.computeRawCSS() - if rawCSS != "" { - // create - - - - - -- Here is some more information: - -
block. - if d != "" && d[0] == '\r' { - d = d[1:] - } - if d != "" && d[0] == '\n' { - d = d[1:] - } - } - } - d = strings.Replace(d, "\x00", "", -1) - if d == "" { - return true - } - p.reconstructActiveFormattingElements() - p.addText(d) - if p.framesetOK && strings.TrimLeft(d, whitespace) != "" { - // There were non-whitespace characters inserted. - p.framesetOK = false - } - case StartTagToken: - switch p.tok.DataAtom { - case a.Html: - copyAttributes(p.oe[0], p.tok) - case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title: - return inHeadIM(p) - case a.Body: - if len(p.oe) >= 2 { - body := p.oe[1] - if body.Type == ElementNode && body.DataAtom == a.Body { - p.framesetOK = false - copyAttributes(body, p.tok) - } - } - case a.Frameset: - if !p.framesetOK || len(p.oe) < 2 || p.oe[1].DataAtom != a.Body { - // Ignore the token. - return true - } - body := p.oe[1] - if body.Parent != nil { - body.Parent.RemoveChild(body) - } - p.oe = p.oe[:1] - p.addElement() - p.im = inFramesetIM - return true - case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Menu, a.Nav, a.Ol, a.P, a.Section, a.Summary, a.Ul: - p.popUntil(buttonScope, a.P) - p.addElement() - case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6: - p.popUntil(buttonScope, a.P) - switch n := p.top(); n.DataAtom { - case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6: - p.oe.pop() - } - p.addElement() - case a.Pre, a.Listing: - p.popUntil(buttonScope, a.P) - p.addElement() - // The newline, if any, will be dealt with by the TextToken case. - p.framesetOK = false - case a.Form: - if p.form == nil { - p.popUntil(buttonScope, a.P) - p.addElement() - p.form = p.top() - } - case a.Li: - p.framesetOK = false - for i := len(p.oe) - 1; i >= 0; i-- { - node := p.oe[i] - switch node.DataAtom { - case a.Li: - p.oe = p.oe[:i] - case a.Address, a.Div, a.P: - continue - default: - if !isSpecialElement(node) { - continue - } - } - break - } - p.popUntil(buttonScope, a.P) - p.addElement() - case a.Dd, a.Dt: - p.framesetOK = false - for i := len(p.oe) - 1; i >= 0; i-- { - node := p.oe[i] - switch node.DataAtom { - case a.Dd, a.Dt: - p.oe = p.oe[:i] - case a.Address, a.Div, a.P: - continue - default: - if !isSpecialElement(node) { - continue - } - } - break - } - p.popUntil(buttonScope, a.P) - p.addElement() - case a.Plaintext: - p.popUntil(buttonScope, a.P) - p.addElement() - case a.Button: - p.popUntil(defaultScope, a.Button) - p.reconstructActiveFormattingElements() - p.addElement() - p.framesetOK = false - case a.A: - for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- { - if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A { - p.inBodyEndTagFormatting(a.A) - p.oe.remove(n) - p.afe.remove(n) - break - } - } - p.reconstructActiveFormattingElements() - p.addFormattingElement() - case a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U: - p.reconstructActiveFormattingElements() - p.addFormattingElement() - case a.Nobr: - p.reconstructActiveFormattingElements() - if p.elementInScope(defaultScope, a.Nobr) { - p.inBodyEndTagFormatting(a.Nobr) - p.reconstructActiveFormattingElements() - } - p.addFormattingElement() - case a.Applet, a.Marquee, a.Object: - p.reconstructActiveFormattingElements() - p.addElement() - p.afe = append(p.afe, &scopeMarker) - p.framesetOK = false - case a.Table: - if !p.quirks { - p.popUntil(buttonScope, a.P) - } - p.addElement() - p.framesetOK = false - p.im = inTableIM - return true - case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr: - p.reconstructActiveFormattingElements() - p.addElement() - p.oe.pop() - p.acknowledgeSelfClosingTag() - if p.tok.DataAtom == a.Input { - for _, t := range p.tok.Attr { - if t.Key == "type" { - if strings.ToLower(t.Val) == "hidden" { - // Skip setting framesetOK = false - return true - } - } - } - } - p.framesetOK = false - case a.Param, a.Source, a.Track: - p.addElement() - p.oe.pop() - p.acknowledgeSelfClosingTag() - case a.Hr: - p.popUntil(buttonScope, a.P) - p.addElement() - p.oe.pop() - p.acknowledgeSelfClosingTag() - p.framesetOK = false - case a.Image: - p.tok.DataAtom = a.Img - p.tok.Data = a.Img.String() - return false - case a.Isindex: - if p.form != nil { - // Ignore the token. - return true - } - action := "" - prompt := "This is a searchable index. Enter search keywords: " - attr := []Attribute{{Key: "name", Val: "isindex"}} - for _, t := range p.tok.Attr { - switch t.Key { - case "action": - action = t.Val - case "name": - // Ignore the attribute. - case "prompt": - prompt = t.Val - default: - attr = append(attr, t) - } - } - p.acknowledgeSelfClosingTag() - p.popUntil(buttonScope, a.P) - p.parseImpliedToken(StartTagToken, a.Form, a.Form.String()) - if action != "" { - p.form.Attr = []Attribute{{Key: "action", Val: action}} - } - p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String()) - p.parseImpliedToken(StartTagToken, a.Label, a.Label.String()) - p.addText(prompt) - p.addChild(&Node{ - Type: ElementNode, - DataAtom: a.Input, - Data: a.Input.String(), - Attr: attr, - }) - p.oe.pop() - p.parseImpliedToken(EndTagToken, a.Label, a.Label.String()) - p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String()) - p.parseImpliedToken(EndTagToken, a.Form, a.Form.String()) - case a.Textarea: - p.addElement() - p.setOriginalIM() - p.framesetOK = false - p.im = textIM - case a.Xmp: - p.popUntil(buttonScope, a.P) - p.reconstructActiveFormattingElements() - p.framesetOK = false - p.addElement() - p.setOriginalIM() - p.im = textIM - case a.Iframe: - p.framesetOK = false - p.addElement() - p.setOriginalIM() - p.im = textIM - case a.Noembed, a.Noscript: - p.addElement() - p.setOriginalIM() - p.im = textIM - case a.Select: - p.reconstructActiveFormattingElements() - p.addElement() - p.framesetOK = false - p.im = inSelectIM - return true - case a.Optgroup, a.Option: - if p.top().DataAtom == a.Option { - p.oe.pop() - } - p.reconstructActiveFormattingElements() - p.addElement() - case a.Rp, a.Rt: - if p.elementInScope(defaultScope, a.Ruby) { - p.generateImpliedEndTags() - } - p.addElement() - case a.Math, a.Svg: - p.reconstructActiveFormattingElements() - if p.tok.DataAtom == a.Math { - adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments) - } else { - adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments) - } - adjustForeignAttributes(p.tok.Attr) - p.addElement() - p.top().Namespace = p.tok.Data - if p.hasSelfClosingToken { - p.oe.pop() - p.acknowledgeSelfClosingTag() - } - return true - case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr: - // Ignore the token. - default: - p.reconstructActiveFormattingElements() - p.addElement() - } - case EndTagToken: - switch p.tok.DataAtom { - case a.Body: - if p.elementInScope(defaultScope, a.Body) { - p.im = afterBodyIM - } - case a.Html: - if p.elementInScope(defaultScope, a.Body) { - p.parseImpliedToken(EndTagToken, a.Body, a.Body.String()) - return false - } - return true - case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul: - p.popUntil(defaultScope, p.tok.DataAtom) - case a.Form: - node := p.form - p.form = nil - i := p.indexOfElementInScope(defaultScope, a.Form) - if node == nil || i == -1 || p.oe[i] != node { - // Ignore the token. - return true - } - p.generateImpliedEndTags() - p.oe.remove(node) - case a.P: - if !p.elementInScope(buttonScope, a.P) { - p.parseImpliedToken(StartTagToken, a.P, a.P.String()) - } - p.popUntil(buttonScope, a.P) - case a.Li: - p.popUntil(listItemScope, a.Li) - case a.Dd, a.Dt: - p.popUntil(defaultScope, p.tok.DataAtom) - case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6: - p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6) - case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U: - p.inBodyEndTagFormatting(p.tok.DataAtom) - case a.Applet, a.Marquee, a.Object: - if p.popUntil(defaultScope, p.tok.DataAtom) { - p.clearActiveFormattingElements() - } - case a.Br: - p.tok.Type = StartTagToken - return false - default: - p.inBodyEndTagOther(p.tok.DataAtom) - } - case CommentToken: - p.addChild(&Node{ - Type: CommentNode, - Data: p.tok.Data, - }) - } - - return true -} - -func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) { - // This is the "adoption agency" algorithm, described at - // https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency - - // TODO: this is a fairly literal line-by-line translation of that algorithm. - // Once the code successfully parses the comprehensive test suite, we should - // refactor this code to be more idiomatic. - - // Steps 1-4. The outer loop. - for i := 0; i < 8; i++ { - // Step 5. Find the formatting element. - var formattingElement *Node - for j := len(p.afe) - 1; j >= 0; j-- { - if p.afe[j].Type == scopeMarkerNode { - break - } - if p.afe[j].DataAtom == tagAtom { - formattingElement = p.afe[j] - break - } - } - if formattingElement == nil { - p.inBodyEndTagOther(tagAtom) - return - } - feIndex := p.oe.index(formattingElement) - if feIndex == -1 { - p.afe.remove(formattingElement) - return - } - if !p.elementInScope(defaultScope, tagAtom) { - // Ignore the tag. - return - } - - // Steps 9-10. Find the furthest block. - var furthestBlock *Node - for _, e := range p.oe[feIndex:] { - if isSpecialElement(e) { - furthestBlock = e - break - } - } - if furthestBlock == nil { - e := p.oe.pop() - for e != formattingElement { - e = p.oe.pop() - } - p.afe.remove(e) - return - } - - // Steps 11-12. Find the common ancestor and bookmark node. - commonAncestor := p.oe[feIndex-1] - bookmark := p.afe.index(formattingElement) - - // Step 13. The inner loop. Find the lastNode to reparent. - lastNode := furthestBlock - node := furthestBlock - x := p.oe.index(node) - // Steps 13.1-13.2 - for j := 0; j < 3; j++ { - // Step 13.3. - x-- - node = p.oe[x] - // Step 13.4 - 13.5. - if p.afe.index(node) == -1 { - p.oe.remove(node) - continue - } - // Step 13.6. - if node == formattingElement { - break - } - // Step 13.7. - clone := node.clone() - p.afe[p.afe.index(node)] = clone - p.oe[p.oe.index(node)] = clone - node = clone - // Step 13.8. - if lastNode == furthestBlock { - bookmark = p.afe.index(node) + 1 - } - // Step 13.9. - if lastNode.Parent != nil { - lastNode.Parent.RemoveChild(lastNode) - } - node.AppendChild(lastNode) - // Step 13.10. - lastNode = node - } - - // Step 14. Reparent lastNode to the common ancestor, - // or for misnested table nodes, to the foster parent. - if lastNode.Parent != nil { - lastNode.Parent.RemoveChild(lastNode) - } - switch commonAncestor.DataAtom { - case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr: - p.fosterParent(lastNode) - default: - commonAncestor.AppendChild(lastNode) - } - - // Steps 15-17. Reparent nodes from the furthest block's children - // to a clone of the formatting element. - clone := formattingElement.clone() - reparentChildren(clone, furthestBlock) - furthestBlock.AppendChild(clone) - - // Step 18. Fix up the list of active formatting elements. - if oldLoc := p.afe.index(formattingElement); oldLoc != -1 && oldLoc < bookmark { - // Move the bookmark with the rest of the list. - bookmark-- - } - p.afe.remove(formattingElement) - p.afe.insert(bookmark, clone) - - // Step 19. Fix up the stack of open elements. - p.oe.remove(formattingElement) - p.oe.insert(p.oe.index(furthestBlock)+1, clone) - } -} - -// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM. -// "Any other end tag" handling from 12.2.5.5 The rules for parsing tokens in foreign content -// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign -func (p *parser) inBodyEndTagOther(tagAtom a.Atom) { - for i := len(p.oe) - 1; i >= 0; i-- { - if p.oe[i].DataAtom == tagAtom { - p.oe = p.oe[:i] - break - } - if isSpecialElement(p.oe[i]) { - break - } - } -} - -// Section 12.2.5.4.8. -func textIM(p *parser) bool { - switch p.tok.Type { - case ErrorToken: - p.oe.pop() - case TextToken: - d := p.tok.Data - if n := p.oe.top(); n.DataAtom == a.Textarea && n.FirstChild == nil { - // Ignore a newline at the start of a