Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c583d0991b | ||
|
|
4d0fbfd720 | ||
|
|
d0a0759bca | ||
|
|
972f5685e7 | ||
|
|
36b0166de9 | ||
|
|
b44b8cf3f4 | ||
|
|
3f452f14f2 | ||
|
|
7d86bb66fe | ||
|
|
50cdb4e058 | ||
|
|
1fc8dec04d | ||
|
|
1bb93891f4 | ||
|
|
1e28907f7a | ||
|
|
4b94e83723 |
32
.github/ISSUE_TEMPLATE.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Please describe your issue
|
||||||
|
|
||||||
|
## Is this a bug, an improvement, a proposal or something else?
|
||||||
|
|
||||||
|
- [ ] Bug
|
||||||
|
- [ ] Improvement
|
||||||
|
- [ ] Proposal
|
||||||
|
- [ ] Something else
|
||||||
|
|
||||||
|
|
||||||
|
## Briefly explain your issue
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
## What's the expected behaviour?
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
## What's the actual behaviour?
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
## What are the steps to reproduce the actual behaviour?
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
## Comments
|
||||||
|
|
||||||
31
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
31
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Before creating your Pull Request...
|
||||||
|
|
||||||
|
- New Pull Requests should include a good description of what's being merged.
|
||||||
|
- Ideally, all Pull Requests are preceded by a discussion initiated in an Issue on this repository.
|
||||||
|
- For bug fixes is mandatory to have tests that cover and fail when the bug is present and will pass after this Pull Request.
|
||||||
|
- For changes and improvements, new tests have to be provided to cover the new features.
|
||||||
|
|
||||||
|
|
||||||
|
## What does this change implement/fix?
|
||||||
|
|
||||||
|
... *answer here*
|
||||||
|
|
||||||
|
## Is this a fix or an improvement?
|
||||||
|
|
||||||
|
- [ ] Fix
|
||||||
|
- [ ] Improvement
|
||||||
|
|
||||||
|
## Have discussed this change in an issue?
|
||||||
|
|
||||||
|
- [ ] Yes
|
||||||
|
- [ ] No
|
||||||
|
|
||||||
|
## Was some test failing because of this issue or change needed?
|
||||||
|
|
||||||
|
- [ ] Yes
|
||||||
|
- [ ] No
|
||||||
|
|
||||||
|
## Are you including tests to cover this change?
|
||||||
|
|
||||||
|
- [ ] Yes
|
||||||
|
- [ ] No
|
||||||
@@ -4,6 +4,7 @@ go:
|
|||||||
- 1.6
|
- 1.6
|
||||||
- 1.7
|
- 1.7
|
||||||
- 1.8
|
- 1.8
|
||||||
|
- 1.9
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
|
|||||||
46
CODE_OF_CONDUCT.md
Normal file
46
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to creating a positive environment include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at leonel.quinteros@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||||
|
|
||||||
|
[homepage]: http://contributor-covenant.org
|
||||||
|
[version]: http://contributor-covenant.org/version/1/4/
|
||||||
19
CONTRIBUTING.md
Normal file
19
CONTRIBUTING.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# CONTRIBUTING
|
||||||
|
|
||||||
|
This open source project welcomes everybody that wants to contribute to it by implementing new features, fixing bugs, testing, creating documentation or simply talk about it.
|
||||||
|
|
||||||
|
Most contributions will start by creating a new Issue to discuss what is the contribution about and to agree on the steps to move forward.
|
||||||
|
|
||||||
|
## Issues
|
||||||
|
|
||||||
|
All issues reports are welcome. Open a new Issue whenever you want to report a bug, request a change or make a proposal.
|
||||||
|
|
||||||
|
This should be your start point of contribution.
|
||||||
|
|
||||||
|
|
||||||
|
## Pull Requests
|
||||||
|
|
||||||
|
If you have any changes that can be merged, feel free to send a Pull Request.
|
||||||
|
|
||||||
|
Usually, you'd want to create a new Issue to discuss about the change you want to merge and why it's needed or what it solves.
|
||||||
|
|
||||||
18
Godeps/Godeps.json
generated
18
Godeps/Godeps.json
generated
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"ImportPath": "github.com/leonelquinteros/gotext",
|
|
||||||
"GoVersion": "devel +be9d7f6d87 Fri Jun 16 00:31:25 2017 +0000",
|
|
||||||
"Deps": [
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/mattn/kinako/ast",
|
|
||||||
"Rev": "fbc18625ec69b28ae03b4eea4c349f215840ee09"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/mattn/kinako/parser",
|
|
||||||
"Rev": "fbc18625ec69b28ae03b4eea4c349f215840ee09"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/mattn/kinako/vm",
|
|
||||||
"Rev": "fbc18625ec69b28ae03b4eea4c349f215840ee09"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
5
Godeps/Readme
generated
5
Godeps/Readme
generated
@@ -1,5 +0,0 @@
|
|||||||
This directory tree is generated automatically by godep.
|
|
||||||
|
|
||||||
Please do not edit.
|
|
||||||
|
|
||||||
See https://github.com/tools/godep for more information.
|
|
||||||
15
Gopkg.lock
generated
Normal file
15
Gopkg.lock
generated
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/mattn/kinako"
|
||||||
|
packages = ["ast","parser","vm"]
|
||||||
|
revision = "332c0a7e205a29536e672337a4bea6c7a96b04c1"
|
||||||
|
|
||||||
|
[solve-meta]
|
||||||
|
analyzer-name = "dep"
|
||||||
|
analyzer-version = 1
|
||||||
|
inputs-digest = "d3069fabe2d6f79fe33ad88133e861db84aef0400f6b949c4e64395913b3ae97"
|
||||||
|
solver-name = "gps-cdcl"
|
||||||
|
solver-version = 1
|
||||||
26
Gopkg.toml
Normal file
26
Gopkg.toml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
# Gopkg.toml example
|
||||||
|
#
|
||||||
|
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||||
|
# for detailed Gopkg.toml documentation.
|
||||||
|
#
|
||||||
|
# required = ["github.com/user/thing/cmd/thing"]
|
||||||
|
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project"
|
||||||
|
# version = "1.0.0"
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project2"
|
||||||
|
# branch = "dev"
|
||||||
|
# source = "github.com/myfork/project2"
|
||||||
|
#
|
||||||
|
# [[override]]
|
||||||
|
# name = "github.com/x/y"
|
||||||
|
# version = "2.4.0"
|
||||||
|
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/mattn/kinako"
|
||||||
76
README.md
76
README.md
@@ -116,39 +116,6 @@ A library directory structure can look like:
|
|||||||
And so on...
|
And so on...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# About translation function names
|
|
||||||
|
|
||||||
The standard GNU gettext defines helper functions that maps to the `gettext()` function and it's widely adopted by most implementations.
|
|
||||||
|
|
||||||
The basic translation function is usually `_()` in the form:
|
|
||||||
|
|
||||||
```
|
|
||||||
_("Translate this")
|
|
||||||
```
|
|
||||||
|
|
||||||
In Go, this can't be implemented by a reusable package as the function name has to start with a capital letter in order to be exported.
|
|
||||||
|
|
||||||
Each implementation of this package can declare this helper functions inside their own packages if this function naming are desired/needed:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import "github.com/leonelquinteros/gotext"
|
|
||||||
|
|
||||||
func _(str string, vars ...interface{}) string {
|
|
||||||
return gotext.Get(str, vars...)
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
This is valid and can be used within a package.
|
|
||||||
|
|
||||||
In normal conditions the Go compiler will optimize the calls to `_()` by replacing its content in place of the function call to reduce the function calling overhead.
|
|
||||||
This is a normal Go compiler behavior.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Usage examples
|
# Usage examples
|
||||||
|
|
||||||
## Using package for single language/domain settings
|
## Using package for single language/domain settings
|
||||||
@@ -156,17 +123,20 @@ This is a normal Go compiler behavior.
|
|||||||
For quick/simple translations you can use the package level functions directly.
|
For quick/simple translations you can use the package level functions directly.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/leonelquinteros/gotext"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/leonelquinteros/gotext"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Configure package
|
// Configure package
|
||||||
gotext.Configure("/path/to/locales/root/dir", "en_UK", "domain-name")
|
gotext.Configure("/path/to/locales/root/dir", "en_UK", "domain-name")
|
||||||
|
|
||||||
// Translate text from default domain
|
// Translate text from default domain
|
||||||
println(gotext.Get("My text on 'domain-name' domain"))
|
fmt.Println(gotext.Get("My text on 'domain-name' domain"))
|
||||||
|
|
||||||
// Translate text from a different domain without reconfigure
|
// Translate text from a different domain without reconfigure
|
||||||
println(gotext.GetD("domain2", "Another text on a different domain"))
|
fmt.Println(gotext.GetD("domain2", "Another text on a different domain"))
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -177,7 +147,10 @@ All translation strings support dynamic variables to be inserted without transla
|
|||||||
Use the fmt.Printf syntax (from Go's "fmt" package) to specify how to print the non-translated variable inside the translation string.
|
Use the fmt.Printf syntax (from Go's "fmt" package) to specify how to print the non-translated variable inside the translation string.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/leonelquinteros/gotext"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/leonelquinteros/gotext"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Configure package
|
// Configure package
|
||||||
@@ -187,7 +160,7 @@ func main() {
|
|||||||
name := "John"
|
name := "John"
|
||||||
|
|
||||||
// Translate text with variables
|
// Translate text with variables
|
||||||
println(gotext.Get("Hi, my name is %s", name))
|
fmt.Println(gotext.Get("Hi, my name is %s", name))
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -199,7 +172,10 @@ When having multiple languages/domains/libraries at the same time, you can creat
|
|||||||
so you can handle each settings on their own.
|
so you can handle each settings on their own.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/leonelquinteros/gotext"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/leonelquinteros/gotext"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Create Locale with library path and language code
|
// Create Locale with library path and language code
|
||||||
@@ -209,13 +185,13 @@ func main() {
|
|||||||
l.AddDomain("default")
|
l.AddDomain("default")
|
||||||
|
|
||||||
// Translate text from default domain
|
// Translate text from default domain
|
||||||
println(l.Get("Translate this"))
|
fmt.Println(l.Get("Translate this"))
|
||||||
|
|
||||||
// Load different domain
|
// Load different domain
|
||||||
l.AddDomain("translations")
|
l.AddDomain("translations")
|
||||||
|
|
||||||
// Translate text from domain
|
// Translate text from domain
|
||||||
println(l.GetD("translations", "Translate this"))
|
fmt.Println(l.GetD("translations", "Translate this"))
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -233,7 +209,10 @@ For when you need to work with PO files and strings,
|
|||||||
you can directly use the Po object to parse it and access the translations in there in the same way.
|
you can directly use the Po object to parse it and access the translations in there in the same way.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/leonelquinteros/gotext"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/leonelquinteros/gotext"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Set PO content
|
// Set PO content
|
||||||
@@ -249,10 +228,10 @@ msgstr "This one sets the var: %s"
|
|||||||
`
|
`
|
||||||
|
|
||||||
// Create Po object
|
// Create Po object
|
||||||
po := new(Po)
|
po := new(gotext.Po)
|
||||||
po.Parse(str)
|
po.Parse(str)
|
||||||
|
|
||||||
println(po.Get("Translate this"))
|
fmt.Println(po.Get("Translate this"))
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -266,7 +245,10 @@ as defined in (https://www.gnu.org/savannah-checkouts/gnu/gettext/manual/html_no
|
|||||||
Plural formulas are parsed and evaluated using [Kinako](https://github.com/mattn/kinako)
|
Plural formulas are parsed and evaluated using [Kinako](https://github.com/mattn/kinako)
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/leonelquinteros/gotext"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/leonelquinteros/gotext"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Set PO content
|
// Set PO content
|
||||||
@@ -290,10 +272,10 @@ msgstr[1] "This one is the plural: %s"
|
|||||||
`
|
`
|
||||||
|
|
||||||
// Create Po object
|
// Create Po object
|
||||||
po := new(Po)
|
po := new(gotext.Po)
|
||||||
po.Parse(str)
|
po.Parse(str)
|
||||||
|
|
||||||
println(po.GetN("One with var: %s", "Several with vars: %s", 54, v))
|
fmt.Println(po.GetN("One with var: %s", "Several with vars: %s", 54, v))
|
||||||
// "This one is the plural: Variable"
|
// "This one is the plural: Variable"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
126
gotext.go
126
gotext.go
@@ -3,82 +3,129 @@ Package gotext implements GNU gettext utilities.
|
|||||||
|
|
||||||
For quick/simple translations you can use the package level functions directly.
|
For quick/simple translations you can use the package level functions directly.
|
||||||
|
|
||||||
import "github.com/leonelquinteros/gotext"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/leonelquinteros/gotext"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Configure package
|
// Configure package
|
||||||
gotext.Configure("/path/to/locales/root/dir", "en_UK", "domain-name")
|
gotext.Configure("/path/to/locales/root/dir", "en_UK", "domain-name")
|
||||||
|
|
||||||
// Translate text from default domain
|
// Translate text from default domain
|
||||||
println(gotext.Get("My text on 'domain-name' domain"))
|
fmt.Println(gotext.Get("My text on 'domain-name' domain"))
|
||||||
|
|
||||||
// Translate text from a different domain without reconfigure
|
// Translate text from a different domain without reconfigure
|
||||||
println(gotext.GetD("domain2", "Another text on a different domain"))
|
fmt.Println(gotext.GetD("domain2", "Another text on a different domain"))
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package gotext
|
package gotext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
// Global environment variables
|
// Global environment variables
|
||||||
var (
|
type config struct {
|
||||||
|
sync.RWMutex
|
||||||
|
|
||||||
// Default domain to look at when no domain is specified. Used by package level functions.
|
// Default domain to look at when no domain is specified. Used by package level functions.
|
||||||
domain = "default"
|
domain string
|
||||||
|
|
||||||
// Language set.
|
// Language set.
|
||||||
language = "en_US"
|
language string
|
||||||
|
|
||||||
// Path to library directory where all locale directories and translation files are.
|
// Path to library directory where all locale directories and translation files are.
|
||||||
library = "/usr/local/share/locale"
|
library string
|
||||||
|
|
||||||
// Storage for package level methods
|
// Storage for package level methods
|
||||||
storage *Locale
|
storage *Locale
|
||||||
)
|
}
|
||||||
|
|
||||||
|
var globalConfig *config
|
||||||
|
|
||||||
|
// Init default configuration
|
||||||
|
func init() {
|
||||||
|
globalConfig = &config{
|
||||||
|
domain: "default",
|
||||||
|
language: "en_US",
|
||||||
|
library: "/usr/local/share/locale",
|
||||||
|
storage: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// loadStorage creates a new Locale object at package level based on the Global variables settings.
|
// loadStorage creates a new Locale object at package level based on the Global variables settings.
|
||||||
// It's called automatically when trying to use Get or GetD methods.
|
// It's called automatically when trying to use Get or GetD methods.
|
||||||
func loadStorage(force bool) {
|
func loadStorage(force bool) {
|
||||||
if storage == nil || force {
|
globalConfig.Lock()
|
||||||
storage = NewLocale(library, language)
|
|
||||||
|
if globalConfig.storage == nil || force {
|
||||||
|
globalConfig.storage = NewLocale(globalConfig.library, globalConfig.language)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := storage.domains[domain]; !ok || force {
|
if _, ok := globalConfig.storage.domains[globalConfig.domain]; !ok || force {
|
||||||
storage.AddDomain(domain)
|
globalConfig.storage.AddDomain(globalConfig.domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
globalConfig.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDomain is the domain getter for the package configuration
|
// GetDomain is the domain getter for the package configuration
|
||||||
func GetDomain() string {
|
func GetDomain() string {
|
||||||
return domain
|
globalConfig.RLock()
|
||||||
|
dom := globalConfig.domain
|
||||||
|
globalConfig.RUnlock()
|
||||||
|
|
||||||
|
return dom
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDomain sets the name for the domain to be used at package level.
|
// SetDomain sets the name for the domain to be used at package level.
|
||||||
// It reloads the corresponding translation file.
|
// It reloads the corresponding translation file.
|
||||||
func SetDomain(dom string) {
|
func SetDomain(dom string) {
|
||||||
domain = dom
|
globalConfig.Lock()
|
||||||
|
globalConfig.domain = dom
|
||||||
|
globalConfig.Unlock()
|
||||||
|
|
||||||
loadStorage(true)
|
loadStorage(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLanguage is the language getter for the package configuration
|
// GetLanguage is the language getter for the package configuration
|
||||||
func GetLanguage() string {
|
func GetLanguage() string {
|
||||||
return language
|
globalConfig.RLock()
|
||||||
|
lang := globalConfig.language
|
||||||
|
globalConfig.RUnlock()
|
||||||
|
|
||||||
|
return lang
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLanguage sets the language code to be used at package level.
|
// SetLanguage sets the language code to be used at package level.
|
||||||
// It reloads the corresponding translation file.
|
// It reloads the corresponding translation file.
|
||||||
func SetLanguage(lang string) {
|
func SetLanguage(lang string) {
|
||||||
language = lang
|
globalConfig.Lock()
|
||||||
|
globalConfig.language = lang
|
||||||
|
globalConfig.Unlock()
|
||||||
|
|
||||||
loadStorage(true)
|
loadStorage(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLibrary is the library getter for the package configuration
|
// GetLibrary is the library getter for the package configuration
|
||||||
func GetLibrary() string {
|
func GetLibrary() string {
|
||||||
return library
|
globalConfig.RLock()
|
||||||
|
lib := globalConfig.library
|
||||||
|
globalConfig.RUnlock()
|
||||||
|
|
||||||
|
return lib
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLibrary sets the root path for the loale directories and files to be used at package level.
|
// SetLibrary sets the root path for the loale directories and files to be used at package level.
|
||||||
// It reloads the corresponding translation file.
|
// It reloads the corresponding translation file.
|
||||||
func SetLibrary(lib string) {
|
func SetLibrary(lib string) {
|
||||||
library = lib
|
globalConfig.Lock()
|
||||||
|
globalConfig.library = lib
|
||||||
|
globalConfig.Unlock()
|
||||||
|
|
||||||
loadStorage(true)
|
loadStorage(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,9 +134,13 @@ func SetLibrary(lib string) {
|
|||||||
// This function is recommended to be used when changing more than one setting,
|
// This function is recommended to be used when changing more than one setting,
|
||||||
// as using each setter will introduce a I/O overhead because the translation file will be loaded after each set.
|
// as using each setter will introduce a I/O overhead because the translation file will be loaded after each set.
|
||||||
func Configure(lib, lang, dom string) {
|
func Configure(lib, lang, dom string) {
|
||||||
library = lib
|
globalConfig.Lock()
|
||||||
language = lang
|
|
||||||
domain = dom
|
globalConfig.library = lib
|
||||||
|
globalConfig.language = lang
|
||||||
|
globalConfig.domain = dom
|
||||||
|
|
||||||
|
globalConfig.Unlock()
|
||||||
|
|
||||||
loadStorage(true)
|
loadStorage(true)
|
||||||
}
|
}
|
||||||
@@ -97,13 +148,13 @@ func Configure(lib, lang, dom string) {
|
|||||||
// Get uses the default domain globally set to return the corresponding translation of a given string.
|
// Get uses the default domain globally set to return the corresponding translation of a given string.
|
||||||
// Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.
|
// Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.
|
||||||
func Get(str string, vars ...interface{}) string {
|
func Get(str string, vars ...interface{}) string {
|
||||||
return GetD(domain, str, vars...)
|
return GetD(GetDomain(), str, vars...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetN retrieves the (N)th plural form of translation for the given string in the "default" domain.
|
// GetN retrieves the (N)th plural form of translation for the given string in the default domain.
|
||||||
// Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.
|
// Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.
|
||||||
func GetN(str, plural string, n int, vars ...interface{}) string {
|
func GetN(str, plural string, n int, vars ...interface{}) string {
|
||||||
return GetND("default", str, plural, n, vars...)
|
return GetND(GetDomain(), str, plural, n, vars...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetD returns the corresponding translation in the given domain for a given string.
|
// GetD returns the corresponding translation in the given domain for a given string.
|
||||||
@@ -119,19 +170,23 @@ func GetND(dom, str, plural string, n int, vars ...interface{}) string {
|
|||||||
loadStorage(false)
|
loadStorage(false)
|
||||||
|
|
||||||
// Return translation
|
// Return translation
|
||||||
return storage.GetND(dom, str, plural, n, vars...)
|
globalConfig.RLock()
|
||||||
|
tr := globalConfig.storage.GetND(dom, str, plural, n, vars...)
|
||||||
|
globalConfig.RUnlock()
|
||||||
|
|
||||||
|
return tr
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetC uses the default domain globally set to return the corresponding translation of the given string in the given context.
|
// GetC uses the default domain globally set to return the corresponding translation of the given string in the given context.
|
||||||
// Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.
|
// Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.
|
||||||
func GetC(str, ctx string, vars ...interface{}) string {
|
func GetC(str, ctx string, vars ...interface{}) string {
|
||||||
return GetDC(domain, str, ctx, vars...)
|
return GetDC(GetDomain(), str, ctx, vars...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNC retrieves the (N)th plural form of translation for the given string in the given context in the "default" domain.
|
// GetNC retrieves the (N)th plural form of translation for the given string in the given context in the default domain.
|
||||||
// Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.
|
// Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.
|
||||||
func GetNC(str, plural string, n int, ctx string, vars ...interface{}) string {
|
func GetNC(str, plural string, n int, ctx string, vars ...interface{}) string {
|
||||||
return GetNDC("default", str, plural, n, ctx, vars...)
|
return GetNDC(GetDomain(), str, plural, n, ctx, vars...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDC returns the corresponding translation in the given domain for the given string in the given context.
|
// GetDC returns the corresponding translation in the given domain for the given string in the given context.
|
||||||
@@ -147,5 +202,18 @@ func GetNDC(dom, str, plural string, n int, ctx string, vars ...interface{}) str
|
|||||||
loadStorage(false)
|
loadStorage(false)
|
||||||
|
|
||||||
// Return translation
|
// Return translation
|
||||||
return storage.GetNDC(dom, str, plural, n, ctx, vars...)
|
globalConfig.RLock()
|
||||||
|
tr := globalConfig.storage.GetNDC(dom, str, plural, n, ctx, vars...)
|
||||||
|
globalConfig.RUnlock()
|
||||||
|
|
||||||
|
return tr
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf applies text formatting only when needed to parse variables.
|
||||||
|
func printf(str string, vars ...interface{}) string {
|
||||||
|
if len(vars) > 0 {
|
||||||
|
return fmt.Sprintf(str, vars...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
}
|
}
|
||||||
|
|||||||
242
gotext_test.go
242
gotext_test.go
@@ -3,6 +3,7 @@ package gotext
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,10 +33,12 @@ func TestGettersSetters(t *testing.T) {
|
|||||||
func TestPackageFunctions(t *testing.T) {
|
func TestPackageFunctions(t *testing.T) {
|
||||||
// Set PO content
|
// Set PO content
|
||||||
str := `
|
str := `
|
||||||
# msgid ""
|
msgid ""
|
||||||
# msgstr ""
|
msgstr "Project-Id-Version: %s\n"
|
||||||
|
"Report-Msgid-Bugs-To: %s\n"
|
||||||
|
|
||||||
# Initial comment
|
# Initial comment
|
||||||
# Headers below
|
# More Headers below
|
||||||
"Language: en\n"
|
"Language: en\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -55,14 +58,6 @@ msgstr[0] "This one is the singular: %s"
|
|||||||
msgstr[1] "This one is the plural: %s"
|
msgstr[1] "This one is the plural: %s"
|
||||||
msgstr[2] "And this is the second plural form: %s"
|
msgstr[2] "And this is the second plural form: %s"
|
||||||
|
|
||||||
msgid "This one has invalid syntax translations"
|
|
||||||
msgid_plural "Plural index"
|
|
||||||
msgstr[abc] "Wrong index"
|
|
||||||
msgstr[1 "Forgot to close brackets"
|
|
||||||
msgstr[0] "Badly formatted string'
|
|
||||||
|
|
||||||
msgid "Invalid formatted id[] with no translations
|
|
||||||
|
|
||||||
msgctxt "Ctx"
|
msgctxt "Ctx"
|
||||||
msgid "One with var: %s"
|
msgid "One with var: %s"
|
||||||
msgid_plural "Several with vars: %s"
|
msgid_plural "Several with vars: %s"
|
||||||
@@ -79,17 +74,22 @@ msgstr "Some random translation in a context"
|
|||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr "More translation"
|
msgstr "More translation"
|
||||||
|
|
||||||
|
msgid "Untranslated"
|
||||||
|
msgid_plural "Several untranslated"
|
||||||
|
msgstr[0] ""
|
||||||
|
msgstr[1] ""
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create Locales directory on default location
|
// Create Locales directory on default location
|
||||||
dirname := path.Clean("/tmp" + string(os.PathSeparator) + "en_US")
|
dirname := path.Join("/tmp", "en_US")
|
||||||
err := os.MkdirAll(dirname, os.ModePerm)
|
err := os.MkdirAll(dirname, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Can't create test directory: %s", err.Error())
|
t.Fatalf("Can't create test directory: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write PO content to default domain file
|
// Write PO content to default domain file
|
||||||
filename := path.Clean(dirname + string(os.PathSeparator) + "default.po")
|
filename := path.Join(dirname, "default.po")
|
||||||
|
|
||||||
f, err := os.Create(filename)
|
f, err := os.Create(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -141,6 +141,181 @@ msgstr "More translation"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUntranslated(t *testing.T) {
|
||||||
|
// Set PO content
|
||||||
|
str := `
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
# Initial comment
|
||||||
|
# Headers below
|
||||||
|
"Language: en\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
msgid "Untranslated"
|
||||||
|
msgid_plural "Several untranslated"
|
||||||
|
msgstr[0] ""
|
||||||
|
msgstr[1] ""
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
// Create Locales directory on default location
|
||||||
|
dirname := path.Join("/tmp", "en_US")
|
||||||
|
err := os.MkdirAll(dirname, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Can't create test directory: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write PO content to default domain file
|
||||||
|
filename := path.Join(dirname, "default.po")
|
||||||
|
|
||||||
|
f, err := os.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Can't create test file: %s", err.Error())
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = f.WriteString(str)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Can't write to test file: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set package configuration
|
||||||
|
Configure("/tmp", "en_US", "default")
|
||||||
|
|
||||||
|
// Test untranslated
|
||||||
|
tr := Get("Untranslated")
|
||||||
|
if tr != "Untranslated" {
|
||||||
|
t.Errorf("Expected 'Untranslated' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
tr = GetN("Untranslated", "Several untranslated", 1)
|
||||||
|
if tr != "Untranslated" {
|
||||||
|
t.Errorf("Expected 'Untranslated' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
tr = GetN("Untranslated", "Several untranslated", 2)
|
||||||
|
if tr != "Several untranslated" {
|
||||||
|
t.Errorf("Expected 'Several untranslated' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
tr = GetD("default", "Untranslated")
|
||||||
|
if tr != "Untranslated" {
|
||||||
|
t.Errorf("Expected 'Untranslated' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
tr = GetND("default", "Untranslated", "Several untranslated", 1)
|
||||||
|
if tr != "Untranslated" {
|
||||||
|
t.Errorf("Expected 'Untranslated' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
tr = GetND("default", "Untranslated", "Several untranslated", 2)
|
||||||
|
if tr != "Several untranslated" {
|
||||||
|
t.Errorf("Expected 'Several untranslated' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDomains(t *testing.T) {
|
||||||
|
// Set PO content
|
||||||
|
strDefault := `
|
||||||
|
msgid ""
|
||||||
|
msgstr "Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
msgid "Default text"
|
||||||
|
msgid_plural "Default texts"
|
||||||
|
msgstr[0] "Default translation"
|
||||||
|
msgstr[1] "Default translations"
|
||||||
|
|
||||||
|
msgctxt "Ctx"
|
||||||
|
msgid "Default context"
|
||||||
|
msgid_plural "Default contexts"
|
||||||
|
msgstr[0] "Default ctx translation"
|
||||||
|
msgstr[1] "Default ctx translations"
|
||||||
|
`
|
||||||
|
|
||||||
|
strCustom := `
|
||||||
|
msgid ""
|
||||||
|
msgstr "Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
msgid "Custom text"
|
||||||
|
msgid_plural "Custom texts"
|
||||||
|
msgstr[0] "Custom translation"
|
||||||
|
msgstr[1] "Custom translations"
|
||||||
|
|
||||||
|
msgctxt "Ctx"
|
||||||
|
msgid "Custom context"
|
||||||
|
msgid_plural "Custom contexts"
|
||||||
|
msgstr[0] "Custom ctx translation"
|
||||||
|
msgstr[1] "Custom ctx translations"
|
||||||
|
`
|
||||||
|
|
||||||
|
// Create Locales directory and files on temp location
|
||||||
|
dirname := path.Join("/tmp", "en_US")
|
||||||
|
err := os.MkdirAll(dirname, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Can't create test directory: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
fDefault, err := os.Create(path.Join(dirname, "default.po"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Can't create test file: %s", err.Error())
|
||||||
|
}
|
||||||
|
defer fDefault.Close()
|
||||||
|
|
||||||
|
fCustom, err := os.Create(path.Join(dirname, "custom.po"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Can't create test file: %s", err.Error())
|
||||||
|
}
|
||||||
|
defer fCustom.Close()
|
||||||
|
|
||||||
|
_, err = fDefault.WriteString(strDefault)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Can't write to test file: %s", err.Error())
|
||||||
|
}
|
||||||
|
_, err = fCustom.WriteString(strCustom)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Can't write to test file: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
Configure("/tmp", "en_US", "default")
|
||||||
|
|
||||||
|
// Check default domain translation
|
||||||
|
SetDomain("default")
|
||||||
|
tr := Get("Default text")
|
||||||
|
if tr != "Default translation" {
|
||||||
|
t.Errorf("Expected 'Default translation'. Got '%s'", tr)
|
||||||
|
}
|
||||||
|
tr = GetN("Default text", "Default texts", 23)
|
||||||
|
if tr != "Default translations" {
|
||||||
|
t.Errorf("Expected 'Default translations'. Got '%s'", tr)
|
||||||
|
}
|
||||||
|
tr = GetC("Default context", "Ctx")
|
||||||
|
if tr != "Default ctx translation" {
|
||||||
|
t.Errorf("Expected 'Default ctx translation'. Got '%s'", tr)
|
||||||
|
}
|
||||||
|
tr = GetNC("Default context", "Default contexts", 23, "Ctx")
|
||||||
|
if tr != "Default ctx translations" {
|
||||||
|
t.Errorf("Expected 'Default ctx translations'. Got '%s'", tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDomain("custom")
|
||||||
|
tr = Get("Custom text")
|
||||||
|
if tr != "Custom translation" {
|
||||||
|
t.Errorf("Expected 'Custom translation'. Got '%s'", tr)
|
||||||
|
}
|
||||||
|
tr = GetN("Custom text", "Custom texts", 23)
|
||||||
|
if tr != "Custom translations" {
|
||||||
|
t.Errorf("Expected 'Custom translations'. Got '%s'", tr)
|
||||||
|
}
|
||||||
|
tr = GetC("Custom context", "Ctx")
|
||||||
|
if tr != "Custom ctx translation" {
|
||||||
|
t.Errorf("Expected 'Custom ctx translation'. Got '%s'", tr)
|
||||||
|
}
|
||||||
|
tr = GetNC("Custom context", "Custom contexts", 23, "Ctx")
|
||||||
|
if tr != "Custom ctx translations" {
|
||||||
|
t.Errorf("Expected 'Custom ctx translations'. Got '%s'", tr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPackageRace(t *testing.T) {
|
func TestPackageRace(t *testing.T) {
|
||||||
// Set PO content
|
// Set PO content
|
||||||
str := `# Some comment
|
str := `# Some comment
|
||||||
@@ -157,17 +332,21 @@ msgstr[0] "This one is the singular: %s"
|
|||||||
msgstr[1] "This one is the plural: %s"
|
msgstr[1] "This one is the plural: %s"
|
||||||
msgstr[2] "And this is the second plural form: %s"
|
msgstr[2] "And this is the second plural form: %s"
|
||||||
|
|
||||||
|
msgctxt "Ctx"
|
||||||
|
msgid "Some random in a context"
|
||||||
|
msgstr "Some random translation in a context"
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create Locales directory on default location
|
// Create Locales directory on default location
|
||||||
dirname := path.Clean(library + string(os.PathSeparator) + "en_US")
|
dirname := path.Join("/tmp", "en_US")
|
||||||
err := os.MkdirAll(dirname, os.ModePerm)
|
err := os.MkdirAll(dirname, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Can't create test directory: %s", err.Error())
|
t.Fatalf("Can't create test directory: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write PO content to default domain file
|
// Write PO content to default domain file
|
||||||
filename := path.Clean(dirname + string(os.PathSeparator) + domain + ".po")
|
filename := path.Join("/tmp", GetDomain()+".po")
|
||||||
|
|
||||||
f, err := os.Create(filename)
|
f, err := os.Create(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -180,20 +359,27 @@ msgstr[2] "And this is the second plural form: %s"
|
|||||||
t.Fatalf("Can't write to test file: %s", err.Error())
|
t.Fatalf("Can't write to test file: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init sync channels
|
var wg sync.WaitGroup
|
||||||
c1 := make(chan bool)
|
|
||||||
c2 := make(chan bool)
|
|
||||||
|
|
||||||
// Test translations
|
for i := 0; i < 1000; i++ {
|
||||||
go func(done chan bool) {
|
wg.Add(1)
|
||||||
Get("My text")
|
// Test translations
|
||||||
done <- true
|
go func() {
|
||||||
}(c1)
|
defer wg.Done()
|
||||||
|
|
||||||
go func(done chan bool) {
|
GetLibrary()
|
||||||
Get("My text")
|
SetLibrary(path.Join("/tmp", "gotextlib"))
|
||||||
done <- true
|
GetDomain()
|
||||||
}(c2)
|
SetDomain("default")
|
||||||
|
GetLanguage()
|
||||||
|
SetLanguage("en_US")
|
||||||
|
Configure("/tmp", "en_US", "default")
|
||||||
|
|
||||||
Get("My text")
|
Get("My text")
|
||||||
|
GetN("One with var: %s", "Several with vars: %s", 0, "test")
|
||||||
|
GetC("Some random in a context", "Ctx")
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|||||||
14
locale.go
14
locale.go
@@ -1,7 +1,6 @@
|
|||||||
package gotext
|
package gotext
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -14,7 +13,10 @@ multiple languages at the same time by working with this object.
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
import "github.com/leonelquinteros/gotext"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/leonelquinteros/gotext"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Create Locale with library path and language code
|
// Create Locale with library path and language code
|
||||||
@@ -24,13 +26,13 @@ Example:
|
|||||||
l.AddDomain("default")
|
l.AddDomain("default")
|
||||||
|
|
||||||
// Translate text from default domain
|
// Translate text from default domain
|
||||||
println(l.Get("Translate this"))
|
fmt.Println(l.Get("Translate this"))
|
||||||
|
|
||||||
// Load different domain ('/path/to/i18n/dir/en_US/LC_MESSAGES/extras.po')
|
// Load different domain ('/path/to/i18n/dir/en_US/LC_MESSAGES/extras.po')
|
||||||
l.AddDomain("extras")
|
l.AddDomain("extras")
|
||||||
|
|
||||||
// Translate text from domain
|
// Translate text from domain
|
||||||
println(l.GetD("extras", "Translate this"))
|
fmt.Println(l.GetD("extras", "Translate this"))
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
@@ -135,7 +137,7 @@ func (l *Locale) GetND(dom, str, plural string, n int, vars ...interface{}) stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return the same we received by default
|
// Return the same we received by default
|
||||||
return fmt.Sprintf(plural, vars...)
|
return printf(plural, vars...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetC uses a domain "default" to return the corresponding translation of the given string in the given context.
|
// GetC uses a domain "default" to return the corresponding translation of the given string in the given context.
|
||||||
@@ -172,5 +174,5 @@ func (l *Locale) GetNDC(dom, str, plural string, n int, ctx string, vars ...inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return the same we received by default
|
// Return the same we received by default
|
||||||
return fmt.Sprintf(plural, vars...)
|
return printf(plural, vars...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
func TestLocale(t *testing.T) {
|
func TestLocale(t *testing.T) {
|
||||||
// Set PO content
|
// Set PO content
|
||||||
str := `
|
str := `
|
||||||
# msgid ""
|
msgid ""
|
||||||
# msgstr ""
|
msgstr ""
|
||||||
# Initial comment
|
# Initial comment
|
||||||
# Headers below
|
# Headers below
|
||||||
"Language: en\n"
|
"Language: en\n"
|
||||||
@@ -38,8 +38,6 @@ msgstr[abc] "Wrong index"
|
|||||||
msgstr[1 "Forgot to close brackets"
|
msgstr[1 "Forgot to close brackets"
|
||||||
msgstr[0] "Badly formatted string'
|
msgstr[0] "Badly formatted string'
|
||||||
|
|
||||||
msgid "Invalid formatted id[] with no translations
|
|
||||||
|
|
||||||
msgctxt "Ctx"
|
msgctxt "Ctx"
|
||||||
msgid "One with var: %s"
|
msgid "One with var: %s"
|
||||||
msgid_plural "Several with vars: %s"
|
msgid_plural "Several with vars: %s"
|
||||||
|
|||||||
142
po.go
142
po.go
@@ -2,7 +2,6 @@ package gotext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"os"
|
"os"
|
||||||
@@ -46,7 +45,12 @@ func (t *translation) getN(n int) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return unstranlated plural by default
|
// Return unstranlated singular if corresponding
|
||||||
|
if n == 0 {
|
||||||
|
return t.id
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return untranslated plural by default
|
||||||
return t.pluralID
|
return t.pluralID
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +61,10 @@ And it's safe for concurrent use by multiple goroutines by using the sync packag
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
import "github.com/leonelquinteros/gotext"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/leonelquinteros/gotext"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Create po object
|
// Create po object
|
||||||
@@ -67,13 +74,13 @@ Example:
|
|||||||
po.ParseFile("/path/to/po/file/translations.po")
|
po.ParseFile("/path/to/po/file/translations.po")
|
||||||
|
|
||||||
// Get translation
|
// Get translation
|
||||||
println(po.Get("Translate this"))
|
fmt.Println(po.Get("Translate this"))
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
type Po struct {
|
type Po struct {
|
||||||
// Headers
|
// Headers storage
|
||||||
RawHeaders string
|
Headers textproto.MIMEHeader
|
||||||
|
|
||||||
// Language header
|
// Language header
|
||||||
Language string
|
Language string
|
||||||
@@ -133,7 +140,6 @@ func (po *Po) ParseFile(f string) {
|
|||||||
func (po *Po) Parse(str string) {
|
func (po *Po) Parse(str string) {
|
||||||
// Lock while parsing
|
// Lock while parsing
|
||||||
po.Lock()
|
po.Lock()
|
||||||
defer po.Unlock()
|
|
||||||
|
|
||||||
// Init storage
|
// Init storage
|
||||||
if po.translations == nil {
|
if po.translations == nil {
|
||||||
@@ -188,7 +194,7 @@ func (po *Po) Parse(str string) {
|
|||||||
|
|
||||||
// Multi line strings and headers
|
// Multi line strings and headers
|
||||||
if strings.HasPrefix(l, "\"") && strings.HasSuffix(l, "\"") {
|
if strings.HasPrefix(l, "\"") && strings.HasSuffix(l, "\"") {
|
||||||
state = po.parseString(l, state)
|
po.parseString(l, state)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,6 +202,9 @@ func (po *Po) Parse(str string) {
|
|||||||
// Save last translation buffer.
|
// Save last translation buffer.
|
||||||
po.saveBuffer()
|
po.saveBuffer()
|
||||||
|
|
||||||
|
// Unlock to parse headers
|
||||||
|
po.Unlock()
|
||||||
|
|
||||||
// Parse headers
|
// Parse headers
|
||||||
po.parseHeaders()
|
po.parseHeaders()
|
||||||
}
|
}
|
||||||
@@ -203,23 +212,24 @@ func (po *Po) Parse(str string) {
|
|||||||
// saveBuffer takes the context and translation buffers
|
// saveBuffer takes the context and translation buffers
|
||||||
// and saves it on the translations collection
|
// and saves it on the translations collection
|
||||||
func (po *Po) saveBuffer() {
|
func (po *Po) saveBuffer() {
|
||||||
// If we have something to save...
|
// With no context...
|
||||||
if po.trBuffer.id != "" {
|
if po.ctxBuffer == "" {
|
||||||
// With no context...
|
po.translations[po.trBuffer.id] = po.trBuffer
|
||||||
if po.ctxBuffer == "" {
|
} else {
|
||||||
po.translations[po.trBuffer.id] = po.trBuffer
|
// With context...
|
||||||
} else {
|
if _, ok := po.contexts[po.ctxBuffer]; !ok {
|
||||||
// With context...
|
po.contexts[po.ctxBuffer] = make(map[string]*translation)
|
||||||
if _, ok := po.contexts[po.ctxBuffer]; !ok {
|
|
||||||
po.contexts[po.ctxBuffer] = make(map[string]*translation)
|
|
||||||
}
|
|
||||||
po.contexts[po.ctxBuffer][po.trBuffer.id] = po.trBuffer
|
|
||||||
}
|
}
|
||||||
|
po.contexts[po.ctxBuffer][po.trBuffer.id] = po.trBuffer
|
||||||
|
|
||||||
// Flush buffer
|
// Cleanup current context buffer if needed
|
||||||
po.trBuffer = newTranslation()
|
if po.trBuffer.id != "" {
|
||||||
po.ctxBuffer = ""
|
po.ctxBuffer = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flush translation buffer
|
||||||
|
po.trBuffer = newTranslation()
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseContext takes a line starting with "msgctxt",
|
// parseContext takes a line starting with "msgctxt",
|
||||||
@@ -279,70 +289,72 @@ func (po *Po) parseMessage(l string) {
|
|||||||
|
|
||||||
// parseString takes a well formatted string without prefix
|
// parseString takes a well formatted string without prefix
|
||||||
// and creates headers or attach multi-line strings when corresponding
|
// and creates headers or attach multi-line strings when corresponding
|
||||||
func (po *Po) parseString(l string, state parseState) parseState {
|
func (po *Po) parseString(l string, state parseState) {
|
||||||
|
clean, _ := strconv.Unquote(l)
|
||||||
|
|
||||||
switch state {
|
switch state {
|
||||||
case msgStr:
|
case msgStr:
|
||||||
// Check for multiline from previously set msgid
|
// Append to last translation found
|
||||||
if po.trBuffer.id != "" {
|
po.trBuffer.trs[len(po.trBuffer.trs)-1] += clean
|
||||||
// Append to last translation found
|
|
||||||
uq, _ := strconv.Unquote(l)
|
|
||||||
po.trBuffer.trs[len(po.trBuffer.trs)-1] += uq
|
|
||||||
|
|
||||||
}
|
|
||||||
case msgID:
|
case msgID:
|
||||||
// Multiline msgid - Append to current id
|
// Multiline msgid - Append to current id
|
||||||
uq, _ := strconv.Unquote(l)
|
po.trBuffer.id += clean
|
||||||
po.trBuffer.id += uq
|
|
||||||
case msgIDPlural:
|
case msgIDPlural:
|
||||||
// Multiline msgid - Append to current id
|
// Multiline msgid - Append to current id
|
||||||
uq, _ := strconv.Unquote(l)
|
po.trBuffer.pluralID += clean
|
||||||
po.trBuffer.pluralID += uq
|
|
||||||
case msgCtxt:
|
case msgCtxt:
|
||||||
// Multiline context - Append to current context
|
// Multiline context - Append to current context
|
||||||
ctxt, _ := strconv.Unquote(l)
|
po.ctxBuffer += clean
|
||||||
po.ctxBuffer += ctxt
|
|
||||||
default:
|
|
||||||
// Otherwise is a header
|
|
||||||
h, _ := strconv.Unquote(strings.TrimSpace(l))
|
|
||||||
po.RawHeaders += h
|
|
||||||
return head
|
|
||||||
}
|
|
||||||
|
|
||||||
return state
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// isValidLine checks for line prefixes to detect valid syntax.
|
// isValidLine checks for line prefixes to detect valid syntax.
|
||||||
func (po *Po) isValidLine(l string) bool {
|
func (po *Po) isValidLine(l string) bool {
|
||||||
// Skip empty lines
|
|
||||||
if l == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check prefix
|
// Check prefix
|
||||||
if !strings.HasPrefix(l, "\"") && !strings.HasPrefix(l, "msgctxt") && !strings.HasPrefix(l, "msgid") && !strings.HasPrefix(l, "msgid_plural") && !strings.HasPrefix(l, "msgstr") {
|
valid := []string{
|
||||||
return false
|
"\"",
|
||||||
|
"msgctxt",
|
||||||
|
"msgid",
|
||||||
|
"msgid_plural",
|
||||||
|
"msgstr",
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
for _, v := range valid {
|
||||||
|
if strings.HasPrefix(l, v) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseHeaders retrieves data from previously parsed headers
|
// parseHeaders retrieves data from previously parsed headers
|
||||||
func (po *Po) parseHeaders() {
|
func (po *Po) parseHeaders() {
|
||||||
// Make sure we end with 2 carriage returns.
|
// Make sure we end with 2 carriage returns.
|
||||||
po.RawHeaders += "\n\n"
|
raw := po.Get("") + "\n\n"
|
||||||
|
|
||||||
// Read
|
// Read
|
||||||
reader := bufio.NewReader(strings.NewReader(po.RawHeaders))
|
reader := bufio.NewReader(strings.NewReader(raw))
|
||||||
tp := textproto.NewReader(reader)
|
tp := textproto.NewReader(reader)
|
||||||
|
|
||||||
mimeHeader, err := tp.ReadMIMEHeader()
|
var err error
|
||||||
|
|
||||||
|
// Sync Headers write.
|
||||||
|
po.Lock()
|
||||||
|
defer po.Unlock()
|
||||||
|
|
||||||
|
po.Headers, err = tp.ReadMIMEHeader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get/save needed headers
|
// Get/save needed headers
|
||||||
po.Language = mimeHeader.Get("Language")
|
po.Language = po.Headers.Get("Language")
|
||||||
po.PluralForms = mimeHeader.Get("Plural-Forms")
|
po.PluralForms = po.Headers.Get("Plural-Forms")
|
||||||
|
|
||||||
// Parse Plural-Forms formula
|
// Parse Plural-Forms formula
|
||||||
if po.PluralForms == "" {
|
if po.PluralForms == "" {
|
||||||
@@ -415,12 +427,12 @@ func (po *Po) Get(str string, vars ...interface{}) string {
|
|||||||
|
|
||||||
if po.translations != nil {
|
if po.translations != nil {
|
||||||
if _, ok := po.translations[str]; ok {
|
if _, ok := po.translations[str]; ok {
|
||||||
return fmt.Sprintf(po.translations[str].get(), vars...)
|
return printf(po.translations[str].get(), vars...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the same we received by default
|
// Return the same we received by default
|
||||||
return fmt.Sprintf(str, vars...)
|
return printf(str, vars...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetN retrieves the (N)th plural form of translation for the given string.
|
// GetN retrieves the (N)th plural form of translation for the given string.
|
||||||
@@ -432,14 +444,14 @@ func (po *Po) GetN(str, plural string, n int, vars ...interface{}) string {
|
|||||||
|
|
||||||
if po.translations != nil {
|
if po.translations != nil {
|
||||||
if _, ok := po.translations[str]; ok {
|
if _, ok := po.translations[str]; ok {
|
||||||
return fmt.Sprintf(po.translations[str].getN(po.pluralForm(n)), vars...)
|
return printf(po.translations[str].getN(po.pluralForm(n)), vars...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if n == 1 {
|
if n == 1 {
|
||||||
return fmt.Sprintf(str, vars...)
|
return printf(str, vars...)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(plural, vars...)
|
return printf(plural, vars...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetC retrieves the corresponding translation for a given string in the given context.
|
// GetC retrieves the corresponding translation for a given string in the given context.
|
||||||
@@ -453,14 +465,14 @@ func (po *Po) GetC(str, ctx string, vars ...interface{}) string {
|
|||||||
if _, ok := po.contexts[ctx]; ok {
|
if _, ok := po.contexts[ctx]; ok {
|
||||||
if po.contexts[ctx] != nil {
|
if po.contexts[ctx] != nil {
|
||||||
if _, ok := po.contexts[ctx][str]; ok {
|
if _, ok := po.contexts[ctx][str]; ok {
|
||||||
return fmt.Sprintf(po.contexts[ctx][str].get(), vars...)
|
return printf(po.contexts[ctx][str].get(), vars...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the string we received by default
|
// Return the string we received by default
|
||||||
return fmt.Sprintf(str, vars...)
|
return printf(str, vars...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNC retrieves the (N)th plural form of translation for the given string in the given context.
|
// GetNC retrieves the (N)th plural form of translation for the given string in the given context.
|
||||||
@@ -474,14 +486,14 @@ func (po *Po) GetNC(str, plural string, n int, ctx string, vars ...interface{})
|
|||||||
if _, ok := po.contexts[ctx]; ok {
|
if _, ok := po.contexts[ctx]; ok {
|
||||||
if po.contexts[ctx] != nil {
|
if po.contexts[ctx] != nil {
|
||||||
if _, ok := po.contexts[ctx][str]; ok {
|
if _, ok := po.contexts[ctx][str]; ok {
|
||||||
return fmt.Sprintf(po.contexts[ctx][str].getN(po.pluralForm(n)), vars...)
|
return printf(po.contexts[ctx][str].getN(po.pluralForm(n)), vars...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if n == 1 {
|
if n == 1 {
|
||||||
return fmt.Sprintf(str, vars...)
|
return printf(str, vars...)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(plural, vars...)
|
return printf(plural, vars...)
|
||||||
}
|
}
|
||||||
|
|||||||
86
po_test.go
86
po_test.go
@@ -9,6 +9,9 @@ import (
|
|||||||
func TestPo(t *testing.T) {
|
func TestPo(t *testing.T) {
|
||||||
// Set PO content
|
// Set PO content
|
||||||
str := `
|
str := `
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
# Initial comment
|
# Initial comment
|
||||||
# Headers below
|
# Headers below
|
||||||
"Language: en\n"
|
"Language: en\n"
|
||||||
@@ -48,14 +51,6 @@ msgstr[0] "This one is the singular: %s"
|
|||||||
msgstr[1] "This one is the plural: %s"
|
msgstr[1] "This one is the plural: %s"
|
||||||
msgstr[2] "And this is the second plural form: %s"
|
msgstr[2] "And this is the second plural form: %s"
|
||||||
|
|
||||||
msgid "This one has invalid syntax translations"
|
|
||||||
msgid_plural "Plural index"
|
|
||||||
msgstr[abc] "Wrong index"
|
|
||||||
msgstr[1 "Forgot to close brackets"
|
|
||||||
msgstr[0] "Badly formatted string'
|
|
||||||
|
|
||||||
msgid "Invalid formatted id[] with no translations
|
|
||||||
|
|
||||||
msgctxt "Ctx"
|
msgctxt "Ctx"
|
||||||
msgid "One with var: %s"
|
msgid "One with var: %s"
|
||||||
msgid_plural "Several with vars: %s"
|
msgid_plural "Several with vars: %s"
|
||||||
@@ -75,11 +70,11 @@ msgstr ""
|
|||||||
msgid "Empty plural form singular"
|
msgid "Empty plural form singular"
|
||||||
msgid_plural "Empty plural form"
|
msgid_plural "Empty plural form"
|
||||||
msgstr[0] "Singular translated"
|
msgstr[0] "Singular translated"
|
||||||
msgstr[1] "
|
msgstr[1] ""
|
||||||
|
|
||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr "More translation"
|
msgstr "More translation"
|
||||||
"
|
|
||||||
`
|
`
|
||||||
|
|
||||||
// Write PO content to file
|
// Write PO content to file
|
||||||
@@ -152,17 +147,6 @@ msgstr "More translation"
|
|||||||
t.Errorf("Expected 'This are tests' but got '%s'", tr)
|
t.Errorf("Expected 'This are tests' but got '%s'", tr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test syntax error parsed translations
|
|
||||||
tr = po.Get("This one has invalid syntax translations")
|
|
||||||
if tr != "This one has invalid syntax translations" {
|
|
||||||
t.Errorf("Expected 'This one has invalid syntax translations' but got '%s'", tr)
|
|
||||||
}
|
|
||||||
|
|
||||||
tr = po.GetN("This one has invalid syntax translations", "This are tests", 4)
|
|
||||||
if tr != "Plural index" {
|
|
||||||
t.Errorf("Expected 'Plural index' but got '%s'", tr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test context translations
|
// Test context translations
|
||||||
v = "Test"
|
v = "Test"
|
||||||
tr = po.GetC("One with var: %s", "Ctx", v)
|
tr = po.GetC("One with var: %s", "Ctx", v)
|
||||||
@@ -214,9 +198,42 @@ msgstr "More translation"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPlural(t *testing.T) {
|
||||||
|
// Set PO content
|
||||||
|
str := `
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
msgid "Singular: %s"
|
||||||
|
msgid_plural "Plural: %s"
|
||||||
|
msgstr[0] "TR Singular: %s"
|
||||||
|
msgstr[1] "TR Plural: %s"
|
||||||
|
msgstr[2] "TR Plural 2: %s"
|
||||||
|
|
||||||
|
|
||||||
|
`
|
||||||
|
// Create po object
|
||||||
|
po := new(Po)
|
||||||
|
po.Parse(str)
|
||||||
|
|
||||||
|
v := "Var"
|
||||||
|
tr := po.GetN("Singular: %s", "Plural: %s", 2, v)
|
||||||
|
if tr != "TR Plural: Var" {
|
||||||
|
t.Errorf("Expected 'TR Plural: Var' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
tr = po.GetN("Singular: %s", "Plural: %s", 1, v)
|
||||||
|
if tr != "TR Singular: Var" {
|
||||||
|
t.Errorf("Expected 'TR Singular: Var' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPoHeaders(t *testing.T) {
|
func TestPoHeaders(t *testing.T) {
|
||||||
// Set PO content
|
// Set PO content
|
||||||
str := `
|
str := `
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
# Initial comment
|
# Initial comment
|
||||||
# Headers below
|
# Headers below
|
||||||
"Language: en\n"
|
"Language: en\n"
|
||||||
@@ -246,9 +263,30 @@ msgstr "Translated example"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMissingPoHeadersSupport(t *testing.T) {
|
||||||
|
// Set PO content
|
||||||
|
str := `
|
||||||
|
msgid "Example"
|
||||||
|
msgstr "Translated example"
|
||||||
|
`
|
||||||
|
|
||||||
|
// Create po object
|
||||||
|
po := new(Po)
|
||||||
|
|
||||||
|
// Parse
|
||||||
|
po.Parse(str)
|
||||||
|
|
||||||
|
// Check translation expected
|
||||||
|
if po.Get("Example") != "Translated example" {
|
||||||
|
t.Errorf("Expected 'Translated example' but got '%s'", po.Get("Example"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPluralFormsSingle(t *testing.T) {
|
func TestPluralFormsSingle(t *testing.T) {
|
||||||
// Single form
|
// Single form
|
||||||
str := `
|
str := `
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
"Plural-Forms: nplurals=1; plural=0;"
|
"Plural-Forms: nplurals=1; plural=0;"
|
||||||
|
|
||||||
# Some comment
|
# Some comment
|
||||||
@@ -292,6 +330,8 @@ msgstr[3] "Plural form 3"
|
|||||||
func TestPluralForms2(t *testing.T) {
|
func TestPluralForms2(t *testing.T) {
|
||||||
// 2 forms
|
// 2 forms
|
||||||
str := `
|
str := `
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;"
|
"Plural-Forms: nplurals=2; plural=n != 1;"
|
||||||
|
|
||||||
# Some comment
|
# Some comment
|
||||||
@@ -331,6 +371,8 @@ msgstr[3] "Plural form 3"
|
|||||||
func TestPluralForms3(t *testing.T) {
|
func TestPluralForms3(t *testing.T) {
|
||||||
// 3 forms
|
// 3 forms
|
||||||
str := `
|
str := `
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;"
|
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;"
|
||||||
|
|
||||||
# Some comment
|
# Some comment
|
||||||
@@ -378,6 +420,8 @@ msgstr[3] "Plural form 3"
|
|||||||
func TestPluralFormsSpecial(t *testing.T) {
|
func TestPluralFormsSpecial(t *testing.T) {
|
||||||
// 3 forms special
|
// 3 forms special
|
||||||
str := `
|
str := `
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
"Plural-Forms: nplurals=3;"
|
"Plural-Forms: nplurals=3;"
|
||||||
"plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
|
"plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
|
||||||
|
|
||||||
|
|||||||
37
vendor/github.com/mattn/kinako/README.md
generated
vendored
Normal file
37
vendor/github.com/mattn/kinako/README.md
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# kinako
|
||||||
|
|
||||||
|
Kinako is small VM written in Go.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
(Picture licensed under CC BY-SA 3.0 by wikipedia)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
Requires Go.
|
||||||
|
```
|
||||||
|
$ go get -u github.com/mattn/kinako
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Embedding the interpreter into your own program:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
var env = vm.NewEnv()
|
||||||
|
|
||||||
|
env.Define("foo", 1)
|
||||||
|
val, err := env.Execute(`foo + 3`)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(val)
|
||||||
|
```
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
||||||
|
# Author
|
||||||
|
|
||||||
|
Yasuhiro Matsumoto (a.k.a mattn)
|
||||||
18
vendor/github.com/mattn/kinako/_example/main.go
generated
vendored
Normal file
18
vendor/github.com/mattn/kinako/_example/main.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/mattn/kinako/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
env := vm.NewEnv()
|
||||||
|
v, err := env.Execute(`foo=1; foo+3`)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(v)
|
||||||
|
}
|
||||||
8
vendor/github.com/mattn/kinako/ast/expr.go
generated
vendored
8
vendor/github.com/mattn/kinako/ast/expr.go
generated
vendored
@@ -75,6 +75,14 @@ type TernaryOpExpr struct {
|
|||||||
Rhs Expr
|
Rhs Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CallExpr provide calling expression.
|
||||||
|
type CallExpr struct {
|
||||||
|
ExprImpl
|
||||||
|
Func interface{}
|
||||||
|
Name string
|
||||||
|
SubExprs []Expr
|
||||||
|
}
|
||||||
|
|
||||||
// ParenExpr provide parent block expression.
|
// ParenExpr provide parent block expression.
|
||||||
type ParenExpr struct {
|
type ParenExpr struct {
|
||||||
ExprImpl
|
ExprImpl
|
||||||
|
|||||||
BIN
vendor/github.com/mattn/kinako/kinako.png
generated
vendored
Normal file
BIN
vendor/github.com/mattn/kinako/kinako.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 450 KiB |
196
vendor/github.com/mattn/kinako/parser/parser.go
generated
vendored
196
vendor/github.com/mattn/kinako/parser/parser.go
generated
vendored
@@ -8,13 +8,14 @@ import (
|
|||||||
"github.com/mattn/kinako/ast"
|
"github.com/mattn/kinako/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
//line parser.go.y:15
|
//line parser.go.y:16
|
||||||
type yySymType struct {
|
type yySymType struct {
|
||||||
yys int
|
yys int
|
||||||
compstmt []ast.Stmt
|
compstmt []ast.Stmt
|
||||||
stmts []ast.Stmt
|
stmts []ast.Stmt
|
||||||
stmt ast.Stmt
|
stmt ast.Stmt
|
||||||
expr ast.Expr
|
expr ast.Expr
|
||||||
|
exprs []ast.Expr
|
||||||
tok ast.Token
|
tok ast.Token
|
||||||
term ast.Token
|
term ast.Token
|
||||||
terms ast.Token
|
terms ast.Token
|
||||||
@@ -82,106 +83,107 @@ const yyEofCode = 1
|
|||||||
const yyErrCode = 2
|
const yyErrCode = 2
|
||||||
const yyInitialStackSize = 16
|
const yyInitialStackSize = 16
|
||||||
|
|
||||||
//line parser.go.y:194
|
//line parser.go.y:213
|
||||||
|
|
||||||
//line yacctab:1
|
//line yacctab:1
|
||||||
var yyExca = [...]int{
|
var yyExca = [...]int{
|
||||||
-1, 1,
|
-1, 1,
|
||||||
1, -1,
|
1, -1,
|
||||||
-2, 0,
|
-2, 0,
|
||||||
-1, 49,
|
-1, 50,
|
||||||
7, 0,
|
7, 0,
|
||||||
8, 0,
|
8, 0,
|
||||||
-2, 20,
|
-2, 20,
|
||||||
-1, 50,
|
-1, 51,
|
||||||
7, 0,
|
7, 0,
|
||||||
8, 0,
|
8, 0,
|
||||||
-2, 21,
|
-2, 21,
|
||||||
}
|
}
|
||||||
|
|
||||||
const yyNprod = 36
|
const yyNprod = 40
|
||||||
const yyPrivate = 57344
|
const yyPrivate = 57344
|
||||||
|
|
||||||
var yyTokenNames []string
|
var yyTokenNames []string
|
||||||
var yyStates []string
|
var yyStates []string
|
||||||
|
|
||||||
const yyLast = 249
|
const yyLast = 251
|
||||||
|
|
||||||
var yyAct = [...]int{
|
var yyAct = [...]int{
|
||||||
|
|
||||||
9, 6, 7, 33, 35, 4, 22, 23, 3, 18,
|
9, 6, 7, 33, 35, 37, 22, 23, 60, 3,
|
||||||
24, 25, 26, 37, 38, 39, 2, 40, 33, 35,
|
24, 25, 26, 38, 39, 40, 1, 41, 33, 35,
|
||||||
17, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
8, 43, 44, 45, 46, 47, 48, 49, 50, 51,
|
||||||
51, 52, 53, 54, 55, 56, 57, 58, 27, 28,
|
52, 53, 54, 55, 56, 57, 58, 59, 61, 42,
|
||||||
30, 32, 34, 36, 8, 1, 21, 60, 0, 29,
|
27, 28, 30, 32, 34, 36, 65, 0, 21, 63,
|
||||||
|
4, 29, 31, 2, 18, 22, 23, 17, 0, 24,
|
||||||
|
25, 26, 64, 0, 66, 0, 67, 33, 35, 27,
|
||||||
|
28, 30, 32, 34, 36, 0, 0, 21, 0, 0,
|
||||||
|
29, 31, 0, 0, 22, 23, 0, 0, 24, 25,
|
||||||
|
26, 0, 0, 0, 0, 62, 33, 35, 27, 28,
|
||||||
|
30, 32, 34, 36, 0, 20, 21, 0, 0, 29,
|
||||||
31, 0, 0, 22, 23, 5, 0, 24, 25, 26,
|
31, 0, 0, 22, 23, 5, 0, 24, 25, 26,
|
||||||
19, 61, 0, 41, 0, 33, 35, 27, 28, 30,
|
19, 0, 0, 0, 0, 33, 35, 27, 28, 30,
|
||||||
32, 34, 36, 0, 19, 21, 0, 0, 29, 31,
|
32, 34, 36, 0, 19, 21, 0, 0, 29, 31,
|
||||||
0, 0, 22, 23, 0, 0, 24, 25, 26, 0,
|
0, 0, 22, 23, 0, 0, 24, 25, 26, 0,
|
||||||
0, 0, 0, 59, 33, 35, 27, 28, 30, 32,
|
0, 0, 0, 0, 33, 35, 27, 28, 30, 32,
|
||||||
34, 36, 0, 20, 21, 0, 0, 29, 31, 0,
|
0, 36, 0, 0, 0, 0, 0, 29, 31, 0,
|
||||||
0, 22, 23, 0, 0, 24, 25, 26, 0, 0,
|
0, 22, 23, 0, 0, 24, 25, 26, 27, 28,
|
||||||
0, 0, 0, 33, 35, 27, 28, 30, 32, 34,
|
30, 32, 0, 33, 35, 0, 0, 0, 0, 29,
|
||||||
36, 0, 0, 21, 0, 0, 29, 31, 0, 0,
|
31, 0, 0, 22, 23, 0, 0, 24, 25, 26,
|
||||||
22, 23, 0, 0, 24, 25, 26, 0, 0, 0,
|
30, 32, 10, 11, 15, 33, 35, 0, 0, 29,
|
||||||
0, 0, 33, 35, 27, 28, 30, 32, 0, 36,
|
31, 0, 0, 22, 23, 0, 0, 24, 25, 26,
|
||||||
0, 0, 0, 0, 0, 29, 31, 0, 0, 22,
|
0, 12, 10, 11, 15, 33, 35, 0, 13, 14,
|
||||||
23, 0, 0, 24, 25, 26, 27, 28, 30, 32,
|
16, 24, 25, 26, 6, 7, 0, 0, 0, 33,
|
||||||
0, 33, 35, 0, 0, 0, 0, 29, 31, 0,
|
35, 12, 0, 0, 0, 0, 0, 0, 13, 14,
|
||||||
0, 22, 23, 0, 0, 24, 25, 26, 30, 32,
|
16,
|
||||||
10, 11, 15, 33, 35, 0, 0, 29, 31, 0,
|
|
||||||
0, 22, 23, 0, 0, 24, 25, 26, 0, 12,
|
|
||||||
10, 11, 15, 33, 35, 0, 13, 14, 16, 24,
|
|
||||||
25, 26, 6, 7, 0, 0, 0, 33, 35, 12,
|
|
||||||
0, 0, 0, 0, 0, 0, 13, 14, 16,
|
|
||||||
}
|
}
|
||||||
var yyPact = [...]int{
|
var yyPact = [...]int{
|
||||||
|
|
||||||
-35, -1000, 216, -35, -35, -1000, -1000, -1000, -1000, 89,
|
-35, -1000, 218, -35, -35, -1000, -1000, -1000, -1000, 91,
|
||||||
-1000, -1000, 216, 216, 216, -1000, 216, -1000, 196, -1000,
|
-27, -1000, 218, 218, 218, -1000, 218, -1000, 198, -1000,
|
||||||
216, 216, 216, 216, 216, 216, 216, 216, 216, 216,
|
218, 218, 218, 218, 218, 218, 218, 218, 218, 218,
|
||||||
216, 216, 216, 216, 216, 216, 216, -31, -31, -31,
|
218, 218, 218, 218, 218, 218, 218, 218, -31, -31,
|
||||||
60, -1000, 118, 31, 203, 203, -31, -31, -31, 189,
|
-31, 62, -1000, 120, 33, 205, 205, -31, -31, -31,
|
||||||
189, -16, -16, -16, -16, 118, 147, 118, 169, -1000,
|
191, 191, -16, -16, -16, -16, 120, 149, 120, 171,
|
||||||
216, 118,
|
29, 120, -1000, 218, -1000, 218, 120, 120,
|
||||||
}
|
}
|
||||||
var yyPgo = [...]int{
|
var yyPgo = [...]int{
|
||||||
|
|
||||||
0, 45, 8, 44, 0, 16, 5, 55,
|
0, 16, 9, 20, 0, 8, 53, 50, 115,
|
||||||
}
|
}
|
||||||
var yyR1 = [...]int{
|
var yyR1 = [...]int{
|
||||||
|
|
||||||
0, 1, 1, 2, 2, 3, 3, 4, 4, 4,
|
0, 1, 1, 2, 2, 3, 3, 4, 4, 4,
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||||
5, 5, 6, 6, 7, 7,
|
4, 5, 5, 5, 6, 6, 7, 7, 8, 8,
|
||||||
}
|
}
|
||||||
var yyR2 = [...]int{
|
var yyR2 = [...]int{
|
||||||
|
|
||||||
0, 1, 2, 2, 3, 3, 1, 1, 1, 2,
|
0, 1, 2, 2, 3, 3, 1, 1, 1, 2,
|
||||||
2, 2, 1, 5, 3, 3, 3, 3, 3, 3,
|
2, 2, 1, 5, 3, 3, 3, 3, 3, 3,
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
0, 1, 1, 2, 1, 1,
|
4, 0, 1, 3, 0, 1, 1, 2, 1, 1,
|
||||||
}
|
}
|
||||||
var yyChk = [...]int{
|
var yyChk = [...]int{
|
||||||
|
|
||||||
-1000, -1, -5, -2, -6, -7, 36, 37, -3, -4,
|
-1000, -1, -6, -2, -7, -8, 36, 37, -3, -4,
|
||||||
4, 5, 23, 30, 31, 6, 32, -5, -6, -7,
|
4, 5, 23, 30, 31, 6, 32, -6, -7, -8,
|
||||||
14, 15, 22, 23, 26, 27, 28, 7, 8, 18,
|
14, 15, 22, 23, 26, 27, 28, 7, 8, 18,
|
||||||
9, 19, 10, 34, 11, 35, 12, -4, -4, -4,
|
9, 19, 10, 34, 11, 35, 12, 32, -4, -4,
|
||||||
-4, -3, -4, -4, -4, -4, -4, -4, -4, -4,
|
-4, -4, -3, -4, -4, -4, -4, -4, -4, -4,
|
||||||
-4, -4, -4, -4, -4, -4, -4, -4, -4, 33,
|
-4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
|
||||||
16, -4,
|
-5, -4, 33, 16, 33, 17, -4, -4,
|
||||||
}
|
}
|
||||||
var yyDef = [...]int{
|
var yyDef = [...]int{
|
||||||
|
|
||||||
30, -2, 1, 30, 31, 32, 34, 35, 3, 6,
|
34, -2, 1, 34, 35, 36, 38, 39, 3, 6,
|
||||||
7, 8, 0, 0, 0, 12, 0, 2, 31, 33,
|
7, 8, 0, 0, 0, 12, 0, 2, 35, 37,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 9, 10, 11,
|
0, 0, 0, 0, 0, 0, 0, 31, 9, 10,
|
||||||
0, 4, 5, 0, 15, 16, 17, 18, 19, -2,
|
11, 0, 4, 5, 0, 15, 16, 17, 18, 19,
|
||||||
-2, 22, 23, 24, 25, 26, 27, 28, 29, 14,
|
-2, -2, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||||
0, 13,
|
0, 32, 14, 0, 30, 0, 13, 33,
|
||||||
}
|
}
|
||||||
var yyTok1 = [...]int{
|
var yyTok1 = [...]int{
|
||||||
|
|
||||||
@@ -547,19 +549,19 @@ yydefault:
|
|||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
yyDollar = yyS[yypt-1 : yypt+1]
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
//line parser.go.y:43
|
//line parser.go.y:45
|
||||||
{
|
{
|
||||||
yyVAL.compstmt = nil
|
yyVAL.compstmt = nil
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
yyDollar = yyS[yypt-2 : yypt+1]
|
yyDollar = yyS[yypt-2 : yypt+1]
|
||||||
//line parser.go.y:47
|
//line parser.go.y:49
|
||||||
{
|
{
|
||||||
yyVAL.compstmt = yyDollar[1].stmts
|
yyVAL.compstmt = yyDollar[1].stmts
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
yyDollar = yyS[yypt-2 : yypt+1]
|
yyDollar = yyS[yypt-2 : yypt+1]
|
||||||
//line parser.go.y:53
|
//line parser.go.y:55
|
||||||
{
|
{
|
||||||
yyVAL.stmts = []ast.Stmt{yyDollar[2].stmt}
|
yyVAL.stmts = []ast.Stmt{yyDollar[2].stmt}
|
||||||
if l, ok := yylex.(*Lexer); ok {
|
if l, ok := yylex.(*Lexer); ok {
|
||||||
@@ -568,7 +570,7 @@ yydefault:
|
|||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:60
|
//line parser.go.y:62
|
||||||
{
|
{
|
||||||
if yyDollar[3].stmt != nil {
|
if yyDollar[3].stmt != nil {
|
||||||
yyVAL.stmts = append(yyDollar[1].stmts, yyDollar[3].stmt)
|
yyVAL.stmts = append(yyDollar[1].stmts, yyDollar[3].stmt)
|
||||||
@@ -579,172 +581,196 @@ yydefault:
|
|||||||
}
|
}
|
||||||
case 5:
|
case 5:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:71
|
//line parser.go.y:73
|
||||||
{
|
{
|
||||||
yyVAL.stmt = &ast.LetStmt{Lhs: yyDollar[1].expr, Operator: "=", Rhs: yyDollar[3].expr}
|
yyVAL.stmt = &ast.LetStmt{Lhs: yyDollar[1].expr, Operator: "=", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 6:
|
case 6:
|
||||||
yyDollar = yyS[yypt-1 : yypt+1]
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
//line parser.go.y:75
|
//line parser.go.y:77
|
||||||
{
|
{
|
||||||
yyVAL.stmt = &ast.ExprStmt{Expr: yyDollar[1].expr}
|
yyVAL.stmt = &ast.ExprStmt{Expr: yyDollar[1].expr}
|
||||||
}
|
}
|
||||||
case 7:
|
case 7:
|
||||||
yyDollar = yyS[yypt-1 : yypt+1]
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
//line parser.go.y:81
|
//line parser.go.y:83
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.IdentExpr{Lit: yyDollar[1].tok.Lit}
|
yyVAL.expr = &ast.IdentExpr{Lit: yyDollar[1].tok.Lit}
|
||||||
}
|
}
|
||||||
case 8:
|
case 8:
|
||||||
yyDollar = yyS[yypt-1 : yypt+1]
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
//line parser.go.y:85
|
//line parser.go.y:87
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.NumberExpr{Lit: yyDollar[1].tok.Lit}
|
yyVAL.expr = &ast.NumberExpr{Lit: yyDollar[1].tok.Lit}
|
||||||
}
|
}
|
||||||
case 9:
|
case 9:
|
||||||
yyDollar = yyS[yypt-2 : yypt+1]
|
yyDollar = yyS[yypt-2 : yypt+1]
|
||||||
//line parser.go.y:89
|
//line parser.go.y:91
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.UnaryExpr{Operator: "-", Expr: yyDollar[2].expr}
|
yyVAL.expr = &ast.UnaryExpr{Operator: "-", Expr: yyDollar[2].expr}
|
||||||
}
|
}
|
||||||
case 10:
|
case 10:
|
||||||
yyDollar = yyS[yypt-2 : yypt+1]
|
yyDollar = yyS[yypt-2 : yypt+1]
|
||||||
//line parser.go.y:93
|
//line parser.go.y:95
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.UnaryExpr{Operator: "!", Expr: yyDollar[2].expr}
|
yyVAL.expr = &ast.UnaryExpr{Operator: "!", Expr: yyDollar[2].expr}
|
||||||
}
|
}
|
||||||
case 11:
|
case 11:
|
||||||
yyDollar = yyS[yypt-2 : yypt+1]
|
yyDollar = yyS[yypt-2 : yypt+1]
|
||||||
//line parser.go.y:97
|
//line parser.go.y:99
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.UnaryExpr{Operator: "^", Expr: yyDollar[2].expr}
|
yyVAL.expr = &ast.UnaryExpr{Operator: "^", Expr: yyDollar[2].expr}
|
||||||
}
|
}
|
||||||
case 12:
|
case 12:
|
||||||
yyDollar = yyS[yypt-1 : yypt+1]
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
//line parser.go.y:101
|
//line parser.go.y:103
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.StringExpr{Lit: yyDollar[1].tok.Lit}
|
yyVAL.expr = &ast.StringExpr{Lit: yyDollar[1].tok.Lit}
|
||||||
}
|
}
|
||||||
case 13:
|
case 13:
|
||||||
yyDollar = yyS[yypt-5 : yypt+1]
|
yyDollar = yyS[yypt-5 : yypt+1]
|
||||||
//line parser.go.y:105
|
//line parser.go.y:107
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.TernaryOpExpr{Expr: yyDollar[1].expr, Lhs: yyDollar[3].expr, Rhs: yyDollar[5].expr}
|
yyVAL.expr = &ast.TernaryOpExpr{Expr: yyDollar[1].expr, Lhs: yyDollar[3].expr, Rhs: yyDollar[5].expr}
|
||||||
}
|
}
|
||||||
case 14:
|
case 14:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:109
|
//line parser.go.y:111
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.ParenExpr{SubExpr: yyDollar[2].expr}
|
yyVAL.expr = &ast.ParenExpr{SubExpr: yyDollar[2].expr}
|
||||||
}
|
}
|
||||||
case 15:
|
case 15:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:113
|
//line parser.go.y:115
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "+", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "+", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 16:
|
case 16:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:117
|
//line parser.go.y:119
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "-", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "-", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 17:
|
case 17:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:121
|
//line parser.go.y:123
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "*", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "*", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 18:
|
case 18:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:125
|
//line parser.go.y:127
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "/", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "/", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 19:
|
case 19:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:129
|
//line parser.go.y:131
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "%", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "%", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 20:
|
case 20:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:133
|
//line parser.go.y:135
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "==", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "==", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 21:
|
case 21:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:137
|
//line parser.go.y:139
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "!=", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "!=", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 22:
|
case 22:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:141
|
//line parser.go.y:143
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: ">", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: ">", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 23:
|
case 23:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:145
|
//line parser.go.y:147
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: ">=", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: ">=", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 24:
|
case 24:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:149
|
//line parser.go.y:151
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "<", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "<", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 25:
|
case 25:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:153
|
//line parser.go.y:155
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "<=", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "<=", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 26:
|
case 26:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:157
|
//line parser.go.y:159
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "|", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "|", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 27:
|
case 27:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:161
|
//line parser.go.y:163
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "||", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "||", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 28:
|
case 28:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:165
|
//line parser.go.y:167
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "&", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "&", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
case 29:
|
case 29:
|
||||||
yyDollar = yyS[yypt-3 : yypt+1]
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
//line parser.go.y:169
|
//line parser.go.y:171
|
||||||
{
|
{
|
||||||
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "&&", Rhs: yyDollar[3].expr}
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "&&", Rhs: yyDollar[3].expr}
|
||||||
}
|
}
|
||||||
|
case 30:
|
||||||
|
yyDollar = yyS[yypt-4 : yypt+1]
|
||||||
|
//line parser.go.y:175
|
||||||
|
{
|
||||||
|
yyVAL.expr = &ast.CallExpr{Name: yyDollar[1].tok.Lit, SubExprs: yyDollar[3].exprs}
|
||||||
|
}
|
||||||
|
case 31:
|
||||||
|
yyDollar = yyS[yypt-0 : yypt+1]
|
||||||
|
//line parser.go.y:180
|
||||||
|
{
|
||||||
|
yyVAL.exprs = nil
|
||||||
|
}
|
||||||
case 32:
|
case 32:
|
||||||
yyDollar = yyS[yypt-1 : yypt+1]
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
//line parser.go.y:179
|
//line parser.go.y:184
|
||||||
{
|
{
|
||||||
|
yyVAL.exprs = []ast.Expr{yyDollar[1].expr}
|
||||||
}
|
}
|
||||||
case 33:
|
case 33:
|
||||||
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
|
//line parser.go.y:188
|
||||||
|
{
|
||||||
|
yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[3].expr)
|
||||||
|
}
|
||||||
|
case 36:
|
||||||
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
|
//line parser.go.y:198
|
||||||
|
{
|
||||||
|
}
|
||||||
|
case 37:
|
||||||
yyDollar = yyS[yypt-2 : yypt+1]
|
yyDollar = yyS[yypt-2 : yypt+1]
|
||||||
//line parser.go.y:182
|
//line parser.go.y:201
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
case 34:
|
case 38:
|
||||||
yyDollar = yyS[yypt-1 : yypt+1]
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
//line parser.go.y:187
|
//line parser.go.y:206
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
case 35:
|
case 39:
|
||||||
yyDollar = yyS[yypt-1 : yypt+1]
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
//line parser.go.y:190
|
//line parser.go.y:209
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
vendor/github.com/mattn/kinako/parser/parser.go.y
generated
vendored
19
vendor/github.com/mattn/kinako/parser/parser.go.y
generated
vendored
@@ -11,12 +11,14 @@ import (
|
|||||||
%type<stmts> stmts
|
%type<stmts> stmts
|
||||||
%type<stmt> stmt
|
%type<stmt> stmt
|
||||||
%type<expr> expr
|
%type<expr> expr
|
||||||
|
%type<exprs> exprs
|
||||||
|
|
||||||
%union{
|
%union{
|
||||||
compstmt []ast.Stmt
|
compstmt []ast.Stmt
|
||||||
stmts []ast.Stmt
|
stmts []ast.Stmt
|
||||||
stmt ast.Stmt
|
stmt ast.Stmt
|
||||||
expr ast.Expr
|
expr ast.Expr
|
||||||
|
exprs []ast.Expr
|
||||||
tok ast.Token
|
tok ast.Token
|
||||||
term ast.Token
|
term ast.Token
|
||||||
terms ast.Token
|
terms ast.Token
|
||||||
@@ -169,6 +171,23 @@ expr :
|
|||||||
{
|
{
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "&&", Rhs: $3}
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "&&", Rhs: $3}
|
||||||
}
|
}
|
||||||
|
| IDENT '(' exprs ')'
|
||||||
|
{
|
||||||
|
$$ = &ast.CallExpr{Name: $1.Lit, SubExprs: $3}
|
||||||
|
}
|
||||||
|
|
||||||
|
exprs :
|
||||||
|
{
|
||||||
|
$$ = nil
|
||||||
|
}
|
||||||
|
| expr
|
||||||
|
{
|
||||||
|
$$ = []ast.Expr{$1}
|
||||||
|
}
|
||||||
|
| exprs ',' expr
|
||||||
|
{
|
||||||
|
$$ = append($1, $3)
|
||||||
|
}
|
||||||
|
|
||||||
opt_terms : /* none */
|
opt_terms : /* none */
|
||||||
| terms
|
| terms
|
||||||
|
|||||||
469
vendor/github.com/mattn/kinako/parser/y.output
generated
vendored
469
vendor/github.com/mattn/kinako/parser/y.output
generated
vendored
@@ -1,11 +1,11 @@
|
|||||||
|
|
||||||
state 0
|
state 0
|
||||||
$accept: .compstmt $end
|
$accept: .compstmt $end
|
||||||
opt_terms: . (30)
|
opt_terms: . (34)
|
||||||
|
|
||||||
';' shift 6
|
';' shift 6
|
||||||
'\n' shift 7
|
'\n' shift 7
|
||||||
. reduce 30 (src line 173)
|
. reduce 34 (src line 192)
|
||||||
|
|
||||||
compstmt goto 1
|
compstmt goto 1
|
||||||
stmts goto 3
|
stmts goto 3
|
||||||
@@ -31,7 +31,7 @@ state 2
|
|||||||
'!' shift 13
|
'!' shift 13
|
||||||
'^' shift 14
|
'^' shift 14
|
||||||
'(' shift 16
|
'(' shift 16
|
||||||
. reduce 1 (src line 42)
|
. reduce 1 (src line 44)
|
||||||
|
|
||||||
stmt goto 8
|
stmt goto 8
|
||||||
expr goto 9
|
expr goto 9
|
||||||
@@ -39,48 +39,48 @@ state 2
|
|||||||
state 3
|
state 3
|
||||||
compstmt: stmts.opt_terms
|
compstmt: stmts.opt_terms
|
||||||
stmts: stmts.terms stmt
|
stmts: stmts.terms stmt
|
||||||
opt_terms: . (30)
|
opt_terms: . (34)
|
||||||
|
|
||||||
';' shift 6
|
';' shift 6
|
||||||
'\n' shift 7
|
'\n' shift 7
|
||||||
. reduce 30 (src line 173)
|
. reduce 34 (src line 192)
|
||||||
|
|
||||||
opt_terms goto 17
|
opt_terms goto 17
|
||||||
terms goto 18
|
terms goto 18
|
||||||
term goto 5
|
term goto 5
|
||||||
|
|
||||||
state 4
|
state 4
|
||||||
opt_terms: terms. (31)
|
opt_terms: terms. (35)
|
||||||
terms: terms.term
|
terms: terms.term
|
||||||
|
|
||||||
';' shift 6
|
';' shift 6
|
||||||
'\n' shift 7
|
'\n' shift 7
|
||||||
. reduce 31 (src line 174)
|
. reduce 35 (src line 193)
|
||||||
|
|
||||||
term goto 19
|
term goto 19
|
||||||
|
|
||||||
state 5
|
state 5
|
||||||
terms: term. (32)
|
terms: term. (36)
|
||||||
|
|
||||||
. reduce 32 (src line 178)
|
. reduce 36 (src line 197)
|
||||||
|
|
||||||
|
|
||||||
state 6
|
state 6
|
||||||
term: ';'. (34)
|
term: ';'. (38)
|
||||||
|
|
||||||
. reduce 34 (src line 186)
|
. reduce 38 (src line 205)
|
||||||
|
|
||||||
|
|
||||||
state 7
|
state 7
|
||||||
term: '\n'. (35)
|
term: '\n'. (39)
|
||||||
|
|
||||||
. reduce 35 (src line 189)
|
. reduce 39 (src line 208)
|
||||||
|
|
||||||
|
|
||||||
state 8
|
state 8
|
||||||
stmts: opt_terms stmt. (3)
|
stmts: opt_terms stmt. (3)
|
||||||
|
|
||||||
. reduce 3 (src line 51)
|
. reduce 3 (src line 53)
|
||||||
|
|
||||||
|
|
||||||
state 9
|
state 9
|
||||||
@@ -120,19 +120,21 @@ state 9
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 6 (src line 74)
|
. reduce 6 (src line 76)
|
||||||
|
|
||||||
|
|
||||||
state 10
|
state 10
|
||||||
expr: IDENT. (7)
|
expr: IDENT. (7)
|
||||||
|
expr: IDENT.'(' exprs ')'
|
||||||
|
|
||||||
. reduce 7 (src line 79)
|
'(' shift 37
|
||||||
|
. reduce 7 (src line 81)
|
||||||
|
|
||||||
|
|
||||||
state 11
|
state 11
|
||||||
expr: NUMBER. (8)
|
expr: NUMBER. (8)
|
||||||
|
|
||||||
. reduce 8 (src line 84)
|
. reduce 8 (src line 86)
|
||||||
|
|
||||||
|
|
||||||
state 12
|
state 12
|
||||||
@@ -147,7 +149,7 @@ state 12
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 37
|
expr goto 38
|
||||||
|
|
||||||
state 13
|
state 13
|
||||||
expr: '!'.expr
|
expr: '!'.expr
|
||||||
@@ -161,7 +163,7 @@ state 13
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 38
|
expr goto 39
|
||||||
|
|
||||||
state 14
|
state 14
|
||||||
expr: '^'.expr
|
expr: '^'.expr
|
||||||
@@ -175,12 +177,12 @@ state 14
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 39
|
expr goto 40
|
||||||
|
|
||||||
state 15
|
state 15
|
||||||
expr: STRING. (12)
|
expr: STRING. (12)
|
||||||
|
|
||||||
. reduce 12 (src line 100)
|
. reduce 12 (src line 102)
|
||||||
|
|
||||||
|
|
||||||
state 16
|
state 16
|
||||||
@@ -195,17 +197,17 @@ state 16
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 40
|
expr goto 41
|
||||||
|
|
||||||
state 17
|
state 17
|
||||||
compstmt: stmts opt_terms. (2)
|
compstmt: stmts opt_terms. (2)
|
||||||
|
|
||||||
. reduce 2 (src line 46)
|
. reduce 2 (src line 48)
|
||||||
|
|
||||||
|
|
||||||
state 18
|
state 18
|
||||||
stmts: stmts terms.stmt
|
stmts: stmts terms.stmt
|
||||||
opt_terms: terms. (31)
|
opt_terms: terms. (35)
|
||||||
terms: terms.term
|
terms: terms.term
|
||||||
|
|
||||||
IDENT shift 10
|
IDENT shift 10
|
||||||
@@ -217,16 +219,16 @@ state 18
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
';' shift 6
|
';' shift 6
|
||||||
'\n' shift 7
|
'\n' shift 7
|
||||||
. reduce 31 (src line 174)
|
. reduce 35 (src line 193)
|
||||||
|
|
||||||
stmt goto 41
|
stmt goto 42
|
||||||
expr goto 9
|
expr goto 9
|
||||||
term goto 19
|
term goto 19
|
||||||
|
|
||||||
state 19
|
state 19
|
||||||
terms: terms term. (33)
|
terms: terms term. (37)
|
||||||
|
|
||||||
. reduce 33 (src line 181)
|
. reduce 37 (src line 200)
|
||||||
|
|
||||||
|
|
||||||
state 20
|
state 20
|
||||||
@@ -241,7 +243,7 @@ state 20
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 42
|
expr goto 43
|
||||||
|
|
||||||
state 21
|
state 21
|
||||||
expr: expr '?'.expr ':' expr
|
expr: expr '?'.expr ':' expr
|
||||||
@@ -255,7 +257,7 @@ state 21
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 43
|
expr goto 44
|
||||||
|
|
||||||
state 22
|
state 22
|
||||||
expr: expr '+'.expr
|
expr: expr '+'.expr
|
||||||
@@ -269,7 +271,7 @@ state 22
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 44
|
expr goto 45
|
||||||
|
|
||||||
state 23
|
state 23
|
||||||
expr: expr '-'.expr
|
expr: expr '-'.expr
|
||||||
@@ -283,7 +285,7 @@ state 23
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 45
|
expr goto 46
|
||||||
|
|
||||||
state 24
|
state 24
|
||||||
expr: expr '*'.expr
|
expr: expr '*'.expr
|
||||||
@@ -297,7 +299,7 @@ state 24
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 46
|
expr goto 47
|
||||||
|
|
||||||
state 25
|
state 25
|
||||||
expr: expr '/'.expr
|
expr: expr '/'.expr
|
||||||
@@ -311,7 +313,7 @@ state 25
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 47
|
expr goto 48
|
||||||
|
|
||||||
state 26
|
state 26
|
||||||
expr: expr '%'.expr
|
expr: expr '%'.expr
|
||||||
@@ -325,7 +327,7 @@ state 26
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 48
|
expr goto 49
|
||||||
|
|
||||||
state 27
|
state 27
|
||||||
expr: expr EQEQ.expr
|
expr: expr EQEQ.expr
|
||||||
@@ -339,7 +341,7 @@ state 27
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 49
|
expr goto 50
|
||||||
|
|
||||||
state 28
|
state 28
|
||||||
expr: expr NEQ.expr
|
expr: expr NEQ.expr
|
||||||
@@ -353,7 +355,7 @@ state 28
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 50
|
expr goto 51
|
||||||
|
|
||||||
state 29
|
state 29
|
||||||
expr: expr '>'.expr
|
expr: expr '>'.expr
|
||||||
@@ -367,7 +369,7 @@ state 29
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 51
|
expr goto 52
|
||||||
|
|
||||||
state 30
|
state 30
|
||||||
expr: expr GE.expr
|
expr: expr GE.expr
|
||||||
@@ -381,7 +383,7 @@ state 30
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 52
|
expr goto 53
|
||||||
|
|
||||||
state 31
|
state 31
|
||||||
expr: expr '<'.expr
|
expr: expr '<'.expr
|
||||||
@@ -395,7 +397,7 @@ state 31
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 53
|
expr goto 54
|
||||||
|
|
||||||
state 32
|
state 32
|
||||||
expr: expr LE.expr
|
expr: expr LE.expr
|
||||||
@@ -409,7 +411,7 @@ state 32
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 54
|
expr goto 55
|
||||||
|
|
||||||
state 33
|
state 33
|
||||||
expr: expr '|'.expr
|
expr: expr '|'.expr
|
||||||
@@ -423,7 +425,7 @@ state 33
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 55
|
expr goto 56
|
||||||
|
|
||||||
state 34
|
state 34
|
||||||
expr: expr OROR.expr
|
expr: expr OROR.expr
|
||||||
@@ -437,7 +439,7 @@ state 34
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 56
|
expr goto 57
|
||||||
|
|
||||||
state 35
|
state 35
|
||||||
expr: expr '&'.expr
|
expr: expr '&'.expr
|
||||||
@@ -451,7 +453,7 @@ state 35
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 57
|
expr goto 58
|
||||||
|
|
||||||
state 36
|
state 36
|
||||||
expr: expr ANDAND.expr
|
expr: expr ANDAND.expr
|
||||||
@@ -465,11 +467,27 @@ state 36
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 58
|
expr goto 59
|
||||||
|
|
||||||
37: shift/reduce conflict (shift 33(0), red'n 9(10)) on '|'
|
|
||||||
37: shift/reduce conflict (shift 35(0), red'n 9(10)) on '&'
|
|
||||||
state 37
|
state 37
|
||||||
|
expr: IDENT '('.exprs ')'
|
||||||
|
exprs: . (31)
|
||||||
|
|
||||||
|
IDENT shift 10
|
||||||
|
NUMBER shift 11
|
||||||
|
STRING shift 15
|
||||||
|
'-' shift 12
|
||||||
|
'!' shift 13
|
||||||
|
'^' shift 14
|
||||||
|
'(' shift 16
|
||||||
|
. reduce 31 (src line 179)
|
||||||
|
|
||||||
|
expr goto 61
|
||||||
|
exprs goto 60
|
||||||
|
|
||||||
|
38: shift/reduce conflict (shift 33(0), red'n 9(10)) on '|'
|
||||||
|
38: shift/reduce conflict (shift 35(0), red'n 9(10)) on '&'
|
||||||
|
state 38
|
||||||
expr: '-' expr. (9)
|
expr: '-' expr. (9)
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
@@ -490,12 +508,12 @@ state 37
|
|||||||
|
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 9 (src line 88)
|
. reduce 9 (src line 90)
|
||||||
|
|
||||||
|
|
||||||
38: shift/reduce conflict (shift 33(0), red'n 10(10)) on '|'
|
39: shift/reduce conflict (shift 33(0), red'n 10(10)) on '|'
|
||||||
38: shift/reduce conflict (shift 35(0), red'n 10(10)) on '&'
|
39: shift/reduce conflict (shift 35(0), red'n 10(10)) on '&'
|
||||||
state 38
|
state 39
|
||||||
expr: '!' expr. (10)
|
expr: '!' expr. (10)
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
@@ -516,12 +534,12 @@ state 38
|
|||||||
|
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 10 (src line 92)
|
. reduce 10 (src line 94)
|
||||||
|
|
||||||
|
|
||||||
39: shift/reduce conflict (shift 33(0), red'n 11(10)) on '|'
|
40: shift/reduce conflict (shift 33(0), red'n 11(10)) on '|'
|
||||||
39: shift/reduce conflict (shift 35(0), red'n 11(10)) on '&'
|
40: shift/reduce conflict (shift 35(0), red'n 11(10)) on '&'
|
||||||
state 39
|
state 40
|
||||||
expr: '^' expr. (11)
|
expr: '^' expr. (11)
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
@@ -542,10 +560,10 @@ state 39
|
|||||||
|
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 11 (src line 96)
|
. reduce 11 (src line 98)
|
||||||
|
|
||||||
|
|
||||||
state 40
|
state 41
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: '(' expr.')'
|
expr: '(' expr.')'
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
@@ -578,19 +596,19 @@ state 40
|
|||||||
'*' shift 24
|
'*' shift 24
|
||||||
'/' shift 25
|
'/' shift 25
|
||||||
'%' shift 26
|
'%' shift 26
|
||||||
')' shift 59
|
')' shift 62
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. error
|
. error
|
||||||
|
|
||||||
|
|
||||||
state 41
|
state 42
|
||||||
stmts: stmts terms stmt. (4)
|
stmts: stmts terms stmt. (4)
|
||||||
|
|
||||||
. reduce 4 (src line 59)
|
. reduce 4 (src line 61)
|
||||||
|
|
||||||
|
|
||||||
state 42
|
state 43
|
||||||
stmt: expr '=' expr. (5)
|
stmt: expr '=' expr. (5)
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
@@ -625,10 +643,10 @@ state 42
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 5 (src line 69)
|
. reduce 5 (src line 71)
|
||||||
|
|
||||||
|
|
||||||
state 43
|
state 44
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr '?' expr.':' expr
|
expr: expr '?' expr.':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
@@ -654,7 +672,7 @@ state 43
|
|||||||
OROR shift 34
|
OROR shift 34
|
||||||
ANDAND shift 36
|
ANDAND shift 36
|
||||||
'?' shift 21
|
'?' shift 21
|
||||||
':' shift 60
|
':' shift 63
|
||||||
'>' shift 29
|
'>' shift 29
|
||||||
'<' shift 31
|
'<' shift 31
|
||||||
'+' shift 22
|
'+' shift 22
|
||||||
@@ -667,9 +685,9 @@ state 43
|
|||||||
. error
|
. error
|
||||||
|
|
||||||
|
|
||||||
44: shift/reduce conflict (shift 33(0), red'n 15(8)) on '|'
|
45: shift/reduce conflict (shift 33(0), red'n 15(8)) on '|'
|
||||||
44: shift/reduce conflict (shift 35(0), red'n 15(8)) on '&'
|
45: shift/reduce conflict (shift 35(0), red'n 15(8)) on '&'
|
||||||
state 44
|
state 45
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr '+' expr. (15)
|
expr: expr '+' expr. (15)
|
||||||
@@ -693,12 +711,12 @@ state 44
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 15 (src line 112)
|
. reduce 15 (src line 114)
|
||||||
|
|
||||||
|
|
||||||
45: shift/reduce conflict (shift 33(0), red'n 16(8)) on '|'
|
46: shift/reduce conflict (shift 33(0), red'n 16(8)) on '|'
|
||||||
45: shift/reduce conflict (shift 35(0), red'n 16(8)) on '&'
|
46: shift/reduce conflict (shift 35(0), red'n 16(8)) on '&'
|
||||||
state 45
|
state 46
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -722,12 +740,12 @@ state 45
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 16 (src line 116)
|
. reduce 16 (src line 118)
|
||||||
|
|
||||||
|
|
||||||
46: shift/reduce conflict (shift 33(0), red'n 17(9)) on '|'
|
47: shift/reduce conflict (shift 33(0), red'n 17(9)) on '|'
|
||||||
46: shift/reduce conflict (shift 35(0), red'n 17(9)) on '&'
|
47: shift/reduce conflict (shift 35(0), red'n 17(9)) on '&'
|
||||||
state 46
|
state 47
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -748,12 +766,12 @@ state 46
|
|||||||
|
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 17 (src line 120)
|
. reduce 17 (src line 122)
|
||||||
|
|
||||||
|
|
||||||
47: shift/reduce conflict (shift 33(0), red'n 18(9)) on '|'
|
48: shift/reduce conflict (shift 33(0), red'n 18(9)) on '|'
|
||||||
47: shift/reduce conflict (shift 35(0), red'n 18(9)) on '&'
|
48: shift/reduce conflict (shift 35(0), red'n 18(9)) on '&'
|
||||||
state 47
|
state 48
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -774,12 +792,12 @@ state 47
|
|||||||
|
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 18 (src line 124)
|
. reduce 18 (src line 126)
|
||||||
|
|
||||||
|
|
||||||
48: shift/reduce conflict (shift 33(0), red'n 19(9)) on '|'
|
49: shift/reduce conflict (shift 33(0), red'n 19(9)) on '|'
|
||||||
48: shift/reduce conflict (shift 35(0), red'n 19(9)) on '&'
|
49: shift/reduce conflict (shift 35(0), red'n 19(9)) on '&'
|
||||||
state 48
|
state 49
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -800,12 +818,12 @@ state 48
|
|||||||
|
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 19 (src line 128)
|
. reduce 19 (src line 130)
|
||||||
|
|
||||||
|
|
||||||
49: shift/reduce conflict (shift 33(0), red'n 20(6)) on '|'
|
50: shift/reduce conflict (shift 33(0), red'n 20(6)) on '|'
|
||||||
49: shift/reduce conflict (shift 35(0), red'n 20(6)) on '&'
|
50: shift/reduce conflict (shift 35(0), red'n 20(6)) on '&'
|
||||||
state 49
|
state 50
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -837,12 +855,12 @@ state 49
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 20 (src line 132)
|
. reduce 20 (src line 134)
|
||||||
|
|
||||||
|
|
||||||
50: shift/reduce conflict (shift 33(0), red'n 21(6)) on '|'
|
51: shift/reduce conflict (shift 33(0), red'n 21(6)) on '|'
|
||||||
50: shift/reduce conflict (shift 35(0), red'n 21(6)) on '&'
|
51: shift/reduce conflict (shift 35(0), red'n 21(6)) on '&'
|
||||||
state 50
|
state 51
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -874,12 +892,12 @@ state 50
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 21 (src line 136)
|
. reduce 21 (src line 138)
|
||||||
|
|
||||||
|
|
||||||
51: shift/reduce conflict (shift 33(0), red'n 22(7)) on '|'
|
52: shift/reduce conflict (shift 33(0), red'n 22(7)) on '|'
|
||||||
51: shift/reduce conflict (shift 35(0), red'n 22(7)) on '&'
|
52: shift/reduce conflict (shift 35(0), red'n 22(7)) on '&'
|
||||||
state 51
|
state 52
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -905,12 +923,12 @@ state 51
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 22 (src line 140)
|
. reduce 22 (src line 142)
|
||||||
|
|
||||||
|
|
||||||
52: shift/reduce conflict (shift 33(0), red'n 23(7)) on '|'
|
53: shift/reduce conflict (shift 33(0), red'n 23(7)) on '|'
|
||||||
52: shift/reduce conflict (shift 35(0), red'n 23(7)) on '&'
|
53: shift/reduce conflict (shift 35(0), red'n 23(7)) on '&'
|
||||||
state 52
|
state 53
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -936,12 +954,12 @@ state 52
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 23 (src line 144)
|
. reduce 23 (src line 146)
|
||||||
|
|
||||||
|
|
||||||
53: shift/reduce conflict (shift 33(0), red'n 24(7)) on '|'
|
54: shift/reduce conflict (shift 33(0), red'n 24(7)) on '|'
|
||||||
53: shift/reduce conflict (shift 35(0), red'n 24(7)) on '&'
|
54: shift/reduce conflict (shift 35(0), red'n 24(7)) on '&'
|
||||||
state 53
|
state 54
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -967,12 +985,12 @@ state 53
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 24 (src line 148)
|
. reduce 24 (src line 150)
|
||||||
|
|
||||||
|
|
||||||
54: shift/reduce conflict (shift 33(0), red'n 25(7)) on '|'
|
55: shift/reduce conflict (shift 33(0), red'n 25(7)) on '|'
|
||||||
54: shift/reduce conflict (shift 35(0), red'n 25(7)) on '&'
|
55: shift/reduce conflict (shift 35(0), red'n 25(7)) on '&'
|
||||||
state 54
|
state 55
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -998,26 +1016,26 @@ state 54
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 25 (src line 152)
|
. reduce 25 (src line 154)
|
||||||
|
|
||||||
|
|
||||||
55: shift/reduce conflict (shift 27(6), red'n 26(0)) on EQEQ
|
56: shift/reduce conflict (shift 27(6), red'n 26(0)) on EQEQ
|
||||||
55: shift/reduce conflict (shift 28(6), red'n 26(0)) on NEQ
|
56: shift/reduce conflict (shift 28(6), red'n 26(0)) on NEQ
|
||||||
55: shift/reduce conflict (shift 30(7), red'n 26(0)) on GE
|
56: shift/reduce conflict (shift 30(7), red'n 26(0)) on GE
|
||||||
55: shift/reduce conflict (shift 32(7), red'n 26(0)) on LE
|
56: shift/reduce conflict (shift 32(7), red'n 26(0)) on LE
|
||||||
55: shift/reduce conflict (shift 34(3), red'n 26(0)) on OROR
|
56: shift/reduce conflict (shift 34(3), red'n 26(0)) on OROR
|
||||||
55: shift/reduce conflict (shift 36(4), red'n 26(0)) on ANDAND
|
56: shift/reduce conflict (shift 36(4), red'n 26(0)) on ANDAND
|
||||||
55: shift/reduce conflict (shift 21(2), red'n 26(0)) on '?'
|
56: shift/reduce conflict (shift 21(2), red'n 26(0)) on '?'
|
||||||
55: shift/reduce conflict (shift 29(7), red'n 26(0)) on '>'
|
56: shift/reduce conflict (shift 29(7), red'n 26(0)) on '>'
|
||||||
55: shift/reduce conflict (shift 31(7), red'n 26(0)) on '<'
|
56: shift/reduce conflict (shift 31(7), red'n 26(0)) on '<'
|
||||||
55: shift/reduce conflict (shift 22(8), red'n 26(0)) on '+'
|
56: shift/reduce conflict (shift 22(8), red'n 26(0)) on '+'
|
||||||
55: shift/reduce conflict (shift 23(8), red'n 26(0)) on '-'
|
56: shift/reduce conflict (shift 23(8), red'n 26(0)) on '-'
|
||||||
55: shift/reduce conflict (shift 24(9), red'n 26(0)) on '*'
|
56: shift/reduce conflict (shift 24(9), red'n 26(0)) on '*'
|
||||||
55: shift/reduce conflict (shift 25(9), red'n 26(0)) on '/'
|
56: shift/reduce conflict (shift 25(9), red'n 26(0)) on '/'
|
||||||
55: shift/reduce conflict (shift 26(9), red'n 26(0)) on '%'
|
56: shift/reduce conflict (shift 26(9), red'n 26(0)) on '%'
|
||||||
55: shift/reduce conflict (shift 33(0), red'n 26(0)) on '|'
|
56: shift/reduce conflict (shift 33(0), red'n 26(0)) on '|'
|
||||||
55: shift/reduce conflict (shift 35(0), red'n 26(0)) on '&'
|
56: shift/reduce conflict (shift 35(0), red'n 26(0)) on '&'
|
||||||
state 55
|
state 56
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -1052,12 +1070,12 @@ state 55
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 26 (src line 156)
|
. reduce 26 (src line 158)
|
||||||
|
|
||||||
|
|
||||||
56: shift/reduce conflict (shift 33(0), red'n 27(3)) on '|'
|
57: shift/reduce conflict (shift 33(0), red'n 27(3)) on '|'
|
||||||
56: shift/reduce conflict (shift 35(0), red'n 27(3)) on '&'
|
57: shift/reduce conflict (shift 35(0), red'n 27(3)) on '&'
|
||||||
state 56
|
state 57
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -1090,26 +1108,26 @@ state 56
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 27 (src line 160)
|
. reduce 27 (src line 162)
|
||||||
|
|
||||||
|
|
||||||
57: shift/reduce conflict (shift 27(6), red'n 28(0)) on EQEQ
|
58: shift/reduce conflict (shift 27(6), red'n 28(0)) on EQEQ
|
||||||
57: shift/reduce conflict (shift 28(6), red'n 28(0)) on NEQ
|
58: shift/reduce conflict (shift 28(6), red'n 28(0)) on NEQ
|
||||||
57: shift/reduce conflict (shift 30(7), red'n 28(0)) on GE
|
58: shift/reduce conflict (shift 30(7), red'n 28(0)) on GE
|
||||||
57: shift/reduce conflict (shift 32(7), red'n 28(0)) on LE
|
58: shift/reduce conflict (shift 32(7), red'n 28(0)) on LE
|
||||||
57: shift/reduce conflict (shift 34(3), red'n 28(0)) on OROR
|
58: shift/reduce conflict (shift 34(3), red'n 28(0)) on OROR
|
||||||
57: shift/reduce conflict (shift 36(4), red'n 28(0)) on ANDAND
|
58: shift/reduce conflict (shift 36(4), red'n 28(0)) on ANDAND
|
||||||
57: shift/reduce conflict (shift 21(2), red'n 28(0)) on '?'
|
58: shift/reduce conflict (shift 21(2), red'n 28(0)) on '?'
|
||||||
57: shift/reduce conflict (shift 29(7), red'n 28(0)) on '>'
|
58: shift/reduce conflict (shift 29(7), red'n 28(0)) on '>'
|
||||||
57: shift/reduce conflict (shift 31(7), red'n 28(0)) on '<'
|
58: shift/reduce conflict (shift 31(7), red'n 28(0)) on '<'
|
||||||
57: shift/reduce conflict (shift 22(8), red'n 28(0)) on '+'
|
58: shift/reduce conflict (shift 22(8), red'n 28(0)) on '+'
|
||||||
57: shift/reduce conflict (shift 23(8), red'n 28(0)) on '-'
|
58: shift/reduce conflict (shift 23(8), red'n 28(0)) on '-'
|
||||||
57: shift/reduce conflict (shift 24(9), red'n 28(0)) on '*'
|
58: shift/reduce conflict (shift 24(9), red'n 28(0)) on '*'
|
||||||
57: shift/reduce conflict (shift 25(9), red'n 28(0)) on '/'
|
58: shift/reduce conflict (shift 25(9), red'n 28(0)) on '/'
|
||||||
57: shift/reduce conflict (shift 26(9), red'n 28(0)) on '%'
|
58: shift/reduce conflict (shift 26(9), red'n 28(0)) on '%'
|
||||||
57: shift/reduce conflict (shift 33(0), red'n 28(0)) on '|'
|
58: shift/reduce conflict (shift 33(0), red'n 28(0)) on '|'
|
||||||
57: shift/reduce conflict (shift 35(0), red'n 28(0)) on '&'
|
58: shift/reduce conflict (shift 35(0), red'n 28(0)) on '&'
|
||||||
state 57
|
state 58
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -1144,12 +1162,12 @@ state 57
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 28 (src line 164)
|
. reduce 28 (src line 166)
|
||||||
|
|
||||||
|
|
||||||
58: shift/reduce conflict (shift 33(0), red'n 29(4)) on '|'
|
59: shift/reduce conflict (shift 33(0), red'n 29(4)) on '|'
|
||||||
58: shift/reduce conflict (shift 35(0), red'n 29(4)) on '&'
|
59: shift/reduce conflict (shift 35(0), red'n 29(4)) on '&'
|
||||||
state 58
|
state 59
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
expr: expr.'-' expr
|
expr: expr.'-' expr
|
||||||
@@ -1181,16 +1199,63 @@ state 58
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 29 (src line 168)
|
. reduce 29 (src line 170)
|
||||||
|
|
||||||
|
|
||||||
state 59
|
|
||||||
expr: '(' expr ')'. (14)
|
|
||||||
|
|
||||||
. reduce 14 (src line 108)
|
|
||||||
|
|
||||||
|
|
||||||
state 60
|
state 60
|
||||||
|
expr: IDENT '(' exprs.')'
|
||||||
|
exprs: exprs.',' expr
|
||||||
|
|
||||||
|
',' shift 65
|
||||||
|
')' shift 64
|
||||||
|
. error
|
||||||
|
|
||||||
|
|
||||||
|
state 61
|
||||||
|
expr: expr.'?' expr ':' expr
|
||||||
|
expr: expr.'+' expr
|
||||||
|
expr: expr.'-' expr
|
||||||
|
expr: expr.'*' expr
|
||||||
|
expr: expr.'/' expr
|
||||||
|
expr: expr.'%' expr
|
||||||
|
expr: expr.EQEQ expr
|
||||||
|
expr: expr.NEQ expr
|
||||||
|
expr: expr.'>' expr
|
||||||
|
expr: expr.GE expr
|
||||||
|
expr: expr.'<' expr
|
||||||
|
expr: expr.LE expr
|
||||||
|
expr: expr.'|' expr
|
||||||
|
expr: expr.OROR expr
|
||||||
|
expr: expr.'&' expr
|
||||||
|
expr: expr.ANDAND expr
|
||||||
|
exprs: expr. (32)
|
||||||
|
|
||||||
|
EQEQ shift 27
|
||||||
|
NEQ shift 28
|
||||||
|
GE shift 30
|
||||||
|
LE shift 32
|
||||||
|
OROR shift 34
|
||||||
|
ANDAND shift 36
|
||||||
|
'?' shift 21
|
||||||
|
'>' shift 29
|
||||||
|
'<' shift 31
|
||||||
|
'+' shift 22
|
||||||
|
'-' shift 23
|
||||||
|
'*' shift 24
|
||||||
|
'/' shift 25
|
||||||
|
'%' shift 26
|
||||||
|
'|' shift 33
|
||||||
|
'&' shift 35
|
||||||
|
. reduce 32 (src line 183)
|
||||||
|
|
||||||
|
|
||||||
|
state 62
|
||||||
|
expr: '(' expr ')'. (14)
|
||||||
|
|
||||||
|
. reduce 14 (src line 110)
|
||||||
|
|
||||||
|
|
||||||
|
state 63
|
||||||
expr: expr '?' expr ':'.expr
|
expr: expr '?' expr ':'.expr
|
||||||
|
|
||||||
IDENT shift 10
|
IDENT shift 10
|
||||||
@@ -1202,11 +1267,31 @@ state 60
|
|||||||
'(' shift 16
|
'(' shift 16
|
||||||
. error
|
. error
|
||||||
|
|
||||||
expr goto 61
|
expr goto 66
|
||||||
|
|
||||||
61: shift/reduce conflict (shift 33(0), red'n 13(2)) on '|'
|
state 64
|
||||||
61: shift/reduce conflict (shift 35(0), red'n 13(2)) on '&'
|
expr: IDENT '(' exprs ')'. (30)
|
||||||
state 61
|
|
||||||
|
. reduce 30 (src line 174)
|
||||||
|
|
||||||
|
|
||||||
|
state 65
|
||||||
|
exprs: exprs ','.expr
|
||||||
|
|
||||||
|
IDENT shift 10
|
||||||
|
NUMBER shift 11
|
||||||
|
STRING shift 15
|
||||||
|
'-' shift 12
|
||||||
|
'!' shift 13
|
||||||
|
'^' shift 14
|
||||||
|
'(' shift 16
|
||||||
|
. error
|
||||||
|
|
||||||
|
expr goto 67
|
||||||
|
|
||||||
|
66: shift/reduce conflict (shift 33(0), red'n 13(2)) on '|'
|
||||||
|
66: shift/reduce conflict (shift 35(0), red'n 13(2)) on '&'
|
||||||
|
state 66
|
||||||
expr: expr.'?' expr ':' expr
|
expr: expr.'?' expr ':' expr
|
||||||
expr: expr '?' expr ':' expr. (13)
|
expr: expr '?' expr ':' expr. (13)
|
||||||
expr: expr.'+' expr
|
expr: expr.'+' expr
|
||||||
@@ -1241,18 +1326,56 @@ state 61
|
|||||||
'%' shift 26
|
'%' shift 26
|
||||||
'|' shift 33
|
'|' shift 33
|
||||||
'&' shift 35
|
'&' shift 35
|
||||||
. reduce 13 (src line 104)
|
. reduce 13 (src line 106)
|
||||||
|
|
||||||
|
|
||||||
37 terminals, 8 nonterminals
|
state 67
|
||||||
36 grammar rules, 62/8000 states
|
expr: expr.'?' expr ':' expr
|
||||||
|
expr: expr.'+' expr
|
||||||
|
expr: expr.'-' expr
|
||||||
|
expr: expr.'*' expr
|
||||||
|
expr: expr.'/' expr
|
||||||
|
expr: expr.'%' expr
|
||||||
|
expr: expr.EQEQ expr
|
||||||
|
expr: expr.NEQ expr
|
||||||
|
expr: expr.'>' expr
|
||||||
|
expr: expr.GE expr
|
||||||
|
expr: expr.'<' expr
|
||||||
|
expr: expr.LE expr
|
||||||
|
expr: expr.'|' expr
|
||||||
|
expr: expr.OROR expr
|
||||||
|
expr: expr.'&' expr
|
||||||
|
expr: expr.ANDAND expr
|
||||||
|
exprs: exprs ',' expr. (33)
|
||||||
|
|
||||||
|
EQEQ shift 27
|
||||||
|
NEQ shift 28
|
||||||
|
GE shift 30
|
||||||
|
LE shift 32
|
||||||
|
OROR shift 34
|
||||||
|
ANDAND shift 36
|
||||||
|
'?' shift 21
|
||||||
|
'>' shift 29
|
||||||
|
'<' shift 31
|
||||||
|
'+' shift 22
|
||||||
|
'-' shift 23
|
||||||
|
'*' shift 24
|
||||||
|
'/' shift 25
|
||||||
|
'%' shift 26
|
||||||
|
'|' shift 33
|
||||||
|
'&' shift 35
|
||||||
|
. reduce 33 (src line 187)
|
||||||
|
|
||||||
|
|
||||||
|
37 terminals, 9 nonterminals
|
||||||
|
40 grammar rules, 68/2000 states
|
||||||
66 shift/reduce, 0 reduce/reduce conflicts reported
|
66 shift/reduce, 0 reduce/reduce conflicts reported
|
||||||
57 working sets used
|
58 working sets used
|
||||||
memory: parser 35/120000
|
memory: parser 38/30000
|
||||||
46 extra closures
|
49 extra closures
|
||||||
390 shift entries, 5 exceptions
|
439 shift entries, 5 exceptions
|
||||||
34 goto entries
|
37 goto entries
|
||||||
2 entries saved by goto default
|
2 entries saved by goto default
|
||||||
Optimizer space used: output 249/120000
|
Optimizer space used: output 251/30000
|
||||||
249 table entries, 78 zero
|
251 table entries, 74 zero
|
||||||
maximum spread: 37, maximum offset: 60
|
maximum spread: 37, maximum offset: 65
|
||||||
|
|||||||
83
vendor/github.com/mattn/kinako/vm/vm.go
generated
vendored
83
vendor/github.com/mattn/kinako/vm/vm.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -39,14 +40,6 @@ func (e *Error) Error() string {
|
|||||||
// Func is function interface to reflect functions internaly.
|
// Func is function interface to reflect functions internaly.
|
||||||
type Func func(args ...reflect.Value) (reflect.Value, error)
|
type Func func(args ...reflect.Value) (reflect.Value, error)
|
||||||
|
|
||||||
func (f Func) String() string {
|
|
||||||
return fmt.Sprintf("[Func: %p]", f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToFunc(f Func) reflect.Value {
|
|
||||||
return reflect.ValueOf(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run executes statements in the specified environment.
|
// Run executes statements in the specified environment.
|
||||||
func Run(stmts []ast.Stmt, env *Env) (reflect.Value, error) {
|
func Run(stmts []ast.Stmt, env *Env) (reflect.Value, error) {
|
||||||
rv := NilValue
|
rv := NilValue
|
||||||
@@ -386,6 +379,80 @@ func invokeExpr(expr ast.Expr, env *Env) (reflect.Value, error) {
|
|||||||
default:
|
default:
|
||||||
return NilValue, errors.New("Unknown operator")
|
return NilValue, errors.New("Unknown operator")
|
||||||
}
|
}
|
||||||
|
case *ast.CallExpr:
|
||||||
|
f, err := env.Get(e.Name)
|
||||||
|
if err != nil {
|
||||||
|
return f, err
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []reflect.Value{}
|
||||||
|
for i, expr := range e.SubExprs {
|
||||||
|
arg, err := invokeExpr(expr, env)
|
||||||
|
if err != nil {
|
||||||
|
return arg, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if i < f.Type().NumIn() {
|
||||||
|
if !f.Type().IsVariadic() {
|
||||||
|
it := f.Type().In(i)
|
||||||
|
if arg.Kind().String() == "unsafe.Pointer" {
|
||||||
|
arg = reflect.New(it).Elem()
|
||||||
|
}
|
||||||
|
if arg.Kind() != it.Kind() && arg.IsValid() && arg.Type().ConvertibleTo(it) {
|
||||||
|
arg = arg.Convert(it)
|
||||||
|
} else if arg.Kind() == reflect.Func {
|
||||||
|
if _, isFunc := arg.Interface().(Func); isFunc {
|
||||||
|
rfunc := arg
|
||||||
|
arg = reflect.MakeFunc(it, func(args []reflect.Value) []reflect.Value {
|
||||||
|
for i := range args {
|
||||||
|
args[i] = reflect.ValueOf(args[i])
|
||||||
|
}
|
||||||
|
return rfunc.Call(args)[:it.NumOut()]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if !arg.IsValid() {
|
||||||
|
arg = reflect.Zero(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !arg.IsValid() {
|
||||||
|
arg = NilValue
|
||||||
|
}
|
||||||
|
|
||||||
|
args = append(args, arg)
|
||||||
|
}
|
||||||
|
ret := NilValue
|
||||||
|
fnc := func() {
|
||||||
|
defer func() {
|
||||||
|
if os.Getenv("KINAKO_DEBUG") == "" {
|
||||||
|
if ex := recover(); ex != nil {
|
||||||
|
if e, ok := ex.(error); ok {
|
||||||
|
err = e
|
||||||
|
} else {
|
||||||
|
err = errors.New(fmt.Sprint(ex))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if f.Kind() == reflect.Interface {
|
||||||
|
f = f.Elem()
|
||||||
|
}
|
||||||
|
rets := f.Call(args)
|
||||||
|
if f.Type().NumOut() == 1 {
|
||||||
|
ret = rets[0]
|
||||||
|
} else {
|
||||||
|
var result []interface{}
|
||||||
|
for _, r := range rets {
|
||||||
|
result = append(result, r.Interface())
|
||||||
|
}
|
||||||
|
ret = reflect.ValueOf(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fnc()
|
||||||
|
if err != nil {
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
case *ast.TernaryOpExpr:
|
case *ast.TernaryOpExpr:
|
||||||
rv, err := invokeExpr(e.Expr, env)
|
rv, err := invokeExpr(e.Expr, env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
54
vendor/github.com/mattn/kinako/vm/vm_test.go
generated
vendored
Normal file
54
vendor/github.com/mattn/kinako/vm/vm_test.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExecute(t *testing.T) {
|
||||||
|
e := NewEnv()
|
||||||
|
e.Define("foo", int64(1))
|
||||||
|
e.Define("bar", int64(2))
|
||||||
|
e.Define("baz", int64(3))
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
input string
|
||||||
|
want interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: "foo+bar",
|
||||||
|
want: int64(3),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "foo-bar",
|
||||||
|
want: int64(-1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "foo*bar",
|
||||||
|
want: int64(2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "foo/bar",
|
||||||
|
want: float64(0.5),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "baz*(foo+bar)",
|
||||||
|
want: int64(9),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "baz > 2 ? foo : bar",
|
||||||
|
want: int64(1),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
r, err := e.Execute(tt.input)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
got := r.Interface()
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Fatalf("want %v, but %v:", tt.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user