Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92b69ffa4c | ||
|
|
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.7
|
||||
- 1.8
|
||||
- 1.9
|
||||
- tip
|
||||
|
||||
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...
|
||||
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
## 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.
|
||||
|
||||
```go
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Configure package
|
||||
gotext.Configure("/path/to/locales/root/dir", "en_UK", "domain-name")
|
||||
|
||||
// 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
|
||||
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.
|
||||
|
||||
```go
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Configure package
|
||||
@@ -187,7 +160,7 @@ func main() {
|
||||
name := "John"
|
||||
|
||||
// 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.
|
||||
|
||||
```go
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create Locale with library path and language code
|
||||
@@ -209,13 +185,13 @@ func main() {
|
||||
l.AddDomain("default")
|
||||
|
||||
// Translate text from default domain
|
||||
println(l.Get("Translate this"))
|
||||
fmt.Println(l.Get("Translate this"))
|
||||
|
||||
// Load different domain
|
||||
l.AddDomain("translations")
|
||||
|
||||
// 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.
|
||||
|
||||
```go
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Set PO content
|
||||
@@ -249,10 +228,10 @@ msgstr "This one sets the var: %s"
|
||||
`
|
||||
|
||||
// Create Po object
|
||||
po := new(Po)
|
||||
po := new(gotext.Po)
|
||||
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)
|
||||
|
||||
```go
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Set PO content
|
||||
@@ -290,10 +272,10 @@ msgstr[1] "This one is the plural: %s"
|
||||
`
|
||||
|
||||
// Create Po object
|
||||
po := new(Po)
|
||||
po := new(gotext.Po)
|
||||
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"
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Configure package
|
||||
gotext.Configure("/path/to/locales/root/dir", "en_UK", "domain-name")
|
||||
|
||||
// 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
|
||||
println(gotext.GetD("domain2", "Another text on a different domain"))
|
||||
fmt.Println(gotext.GetD("domain2", "Another text on a different domain"))
|
||||
}
|
||||
|
||||
*/
|
||||
package gotext
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Global environment variables
|
||||
var (
|
||||
type config struct {
|
||||
sync.RWMutex
|
||||
|
||||
// Default domain to look at when no domain is specified. Used by package level functions.
|
||||
domain = "default"
|
||||
domain string
|
||||
|
||||
// Language set.
|
||||
language = "en_US"
|
||||
language string
|
||||
|
||||
// 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 *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.
|
||||
// It's called automatically when trying to use Get or GetD methods.
|
||||
func loadStorage(force bool) {
|
||||
if storage == nil || force {
|
||||
storage = NewLocale(library, language)
|
||||
globalConfig.Lock()
|
||||
|
||||
if globalConfig.storage == nil || force {
|
||||
globalConfig.storage = NewLocale(globalConfig.library, globalConfig.language)
|
||||
}
|
||||
|
||||
if _, ok := storage.domains[domain]; !ok || force {
|
||||
storage.AddDomain(domain)
|
||||
if _, ok := globalConfig.storage.domains[globalConfig.domain]; !ok || force {
|
||||
globalConfig.storage.AddDomain(globalConfig.domain)
|
||||
}
|
||||
|
||||
globalConfig.Unlock()
|
||||
}
|
||||
|
||||
// GetDomain is the domain getter for the package configuration
|
||||
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.
|
||||
// It reloads the corresponding translation file.
|
||||
func SetDomain(dom string) {
|
||||
domain = dom
|
||||
globalConfig.Lock()
|
||||
globalConfig.domain = dom
|
||||
globalConfig.Unlock()
|
||||
|
||||
loadStorage(true)
|
||||
}
|
||||
|
||||
// GetLanguage is the language getter for the package configuration
|
||||
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.
|
||||
// It reloads the corresponding translation file.
|
||||
func SetLanguage(lang string) {
|
||||
language = lang
|
||||
globalConfig.Lock()
|
||||
globalConfig.language = lang
|
||||
globalConfig.Unlock()
|
||||
|
||||
loadStorage(true)
|
||||
}
|
||||
|
||||
// GetLibrary is the library getter for the package configuration
|
||||
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.
|
||||
// It reloads the corresponding translation file.
|
||||
func SetLibrary(lib string) {
|
||||
library = lib
|
||||
globalConfig.Lock()
|
||||
globalConfig.library = lib
|
||||
globalConfig.Unlock()
|
||||
|
||||
loadStorage(true)
|
||||
}
|
||||
|
||||
@@ -87,9 +134,13 @@ func SetLibrary(lib string) {
|
||||
// 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.
|
||||
func Configure(lib, lang, dom string) {
|
||||
library = lib
|
||||
language = lang
|
||||
domain = dom
|
||||
globalConfig.Lock()
|
||||
|
||||
globalConfig.library = lib
|
||||
globalConfig.language = lang
|
||||
globalConfig.domain = dom
|
||||
|
||||
globalConfig.Unlock()
|
||||
|
||||
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.
|
||||
// Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.
|
||||
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.
|
||||
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.
|
||||
@@ -119,19 +170,23 @@ func GetND(dom, str, plural string, n int, vars ...interface{}) string {
|
||||
loadStorage(false)
|
||||
|
||||
// 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.
|
||||
// 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 {
|
||||
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.
|
||||
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.
|
||||
@@ -147,5 +202,18 @@ func GetNDC(dom, str, plural string, n int, ctx string, vars ...interface{}) str
|
||||
loadStorage(false)
|
||||
|
||||
// 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 (
|
||||
"os"
|
||||
"path"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -32,10 +33,12 @@ func TestGettersSetters(t *testing.T) {
|
||||
func TestPackageFunctions(t *testing.T) {
|
||||
// Set PO content
|
||||
str := `
|
||||
# msgid ""
|
||||
# msgstr ""
|
||||
msgid ""
|
||||
msgstr "Project-Id-Version: %s\n"
|
||||
"Report-Msgid-Bugs-To: %s\n"
|
||||
|
||||
# Initial comment
|
||||
# Headers below
|
||||
# More Headers below
|
||||
"Language: en\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\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[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"
|
||||
msgid "One with var: %s"
|
||||
msgid_plural "Several with vars: %s"
|
||||
@@ -79,17 +74,22 @@ msgstr "Some random translation in a context"
|
||||
msgid "More"
|
||||
msgstr "More translation"
|
||||
|
||||
msgid "Untranslated"
|
||||
msgid_plural "Several untranslated"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
`
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't create test directory: %s", err.Error())
|
||||
}
|
||||
|
||||
// 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)
|
||||
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) {
|
||||
// Set PO content
|
||||
str := `# Some comment
|
||||
@@ -157,17 +332,21 @@ msgstr[0] "This one is the singular: %s"
|
||||
msgstr[1] "This one is the plural: %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
|
||||
dirname := path.Clean(library + string(os.PathSeparator) + "en_US")
|
||||
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.Clean(dirname + string(os.PathSeparator) + domain + ".po")
|
||||
filename := path.Join("/tmp", GetDomain()+".po")
|
||||
|
||||
f, err := os.Create(filename)
|
||||
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())
|
||||
}
|
||||
|
||||
// Init sync channels
|
||||
c1 := make(chan bool)
|
||||
c2 := make(chan bool)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// Test translations
|
||||
go func(done chan bool) {
|
||||
Get("My text")
|
||||
done <- true
|
||||
}(c1)
|
||||
for i := 0; i < 1000; i++ {
|
||||
wg.Add(1)
|
||||
// Test translations
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
go func(done chan bool) {
|
||||
Get("My text")
|
||||
done <- true
|
||||
}(c2)
|
||||
GetLibrary()
|
||||
SetLibrary(path.Join("/tmp", "gotextlib"))
|
||||
GetDomain()
|
||||
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()
|
||||
}
|
||||
|
||||
22
locale.go
22
locale.go
@@ -1,7 +1,6 @@
|
||||
package gotext
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"sync"
|
||||
@@ -14,7 +13,10 @@ multiple languages at the same time by working with this object.
|
||||
|
||||
Example:
|
||||
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create Locale with library path and language code
|
||||
@@ -24,13 +26,13 @@ Example:
|
||||
l.AddDomain("default")
|
||||
|
||||
// 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')
|
||||
l.AddDomain("extras")
|
||||
|
||||
// Translate text from domain
|
||||
println(l.GetD("extras", "Translate this"))
|
||||
fmt.Println(l.GetD("extras", "Translate this"))
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -104,13 +106,13 @@ func (l *Locale) AddDomain(dom string) {
|
||||
// Get uses a domain "default" 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.
|
||||
func (l *Locale) Get(str string, vars ...interface{}) string {
|
||||
return l.GetD("default", str, vars...)
|
||||
return l.GetD(GetDomain(), str, vars...)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (l *Locale) GetN(str, plural string, n int, vars ...interface{}) string {
|
||||
return l.GetND("default", str, plural, n, vars...)
|
||||
return l.GetND(GetDomain(), str, plural, n, vars...)
|
||||
}
|
||||
|
||||
// GetD returns the corresponding translation in the given domain for the given string.
|
||||
@@ -135,19 +137,19 @@ func (l *Locale) GetND(dom, str, plural string, n int, vars ...interface{}) stri
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.
|
||||
func (l *Locale) GetC(str, ctx string, vars ...interface{}) string {
|
||||
return l.GetDC("default", str, ctx, vars...)
|
||||
return l.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.
|
||||
// Supports optional parameters (vars... interface{}) to be inserted on the formatted string using the fmt.Printf syntax.
|
||||
func (l *Locale) GetNC(str, plural string, n int, ctx string, vars ...interface{}) string {
|
||||
return l.GetNDC("default", str, plural, n, ctx, vars...)
|
||||
return l.GetNDC(GetDomain(), str, plural, n, ctx, vars...)
|
||||
}
|
||||
|
||||
// GetDC returns the corresponding translation in the given domain for 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 fmt.Sprintf(plural, vars...)
|
||||
return printf(plural, vars...)
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
func TestLocale(t *testing.T) {
|
||||
// Set PO content
|
||||
str := `
|
||||
# msgid ""
|
||||
# msgstr ""
|
||||
msgid ""
|
||||
msgstr ""
|
||||
# Initial comment
|
||||
# Headers below
|
||||
"Language: en\n"
|
||||
@@ -38,8 +38,6 @@ msgstr[abc] "Wrong index"
|
||||
msgstr[1 "Forgot to close brackets"
|
||||
msgstr[0] "Badly formatted string'
|
||||
|
||||
msgid "Invalid formatted id[] with no translations
|
||||
|
||||
msgctxt "Ctx"
|
||||
msgid "One with var: %s"
|
||||
msgid_plural "Several with vars: %s"
|
||||
@@ -88,6 +86,9 @@ msgstr "More translation"
|
||||
// Add domain
|
||||
l.AddDomain("my_domain")
|
||||
|
||||
// Set global domain
|
||||
SetDomain("my_domain")
|
||||
|
||||
// Test translations
|
||||
tr := l.GetD("my_domain", "My text")
|
||||
if tr != "Translated text" {
|
||||
@@ -107,7 +108,17 @@ msgstr "More translation"
|
||||
}
|
||||
|
||||
// Test context translations
|
||||
tr = l.GetC("Some random in a context", "Ctx")
|
||||
if tr != "Some random translation in a context" {
|
||||
t.Errorf("Expected 'Some random translation in a context'. Got '%s'", tr)
|
||||
}
|
||||
|
||||
v = "Test"
|
||||
tr = l.GetNC("One with var: %s", "Several with vars: %s", 23, "Ctx", v)
|
||||
if tr != "This one is the plural in a Ctx context: Test" {
|
||||
t.Errorf("Expected 'This one is the plural in a Ctx context: Test'. Got '%s'", tr)
|
||||
}
|
||||
|
||||
tr = l.GetDC("my_domain", "One with var: %s", "Ctx", v)
|
||||
if tr != "This one is the singular in a Ctx context: Test" {
|
||||
t.Errorf("Expected 'This one is the singular in a Ctx context: Test' but got '%s'", tr)
|
||||
@@ -208,6 +219,9 @@ msgstr "More translation"
|
||||
// Add domain
|
||||
l.AddDomain("my_domain")
|
||||
|
||||
// Set default domain to make it fail
|
||||
SetDomain("default")
|
||||
|
||||
// Test non-existent "deafult" domain responses
|
||||
tr := l.Get("My text")
|
||||
if tr != "My text" {
|
||||
|
||||
142
po.go
142
po.go
@@ -2,7 +2,6 @@ package gotext
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/textproto"
|
||||
"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
|
||||
}
|
||||
|
||||
@@ -57,7 +61,10 @@ And it's safe for concurrent use by multiple goroutines by using the sync packag
|
||||
|
||||
Example:
|
||||
|
||||
import "github.com/leonelquinteros/gotext"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create po object
|
||||
@@ -67,13 +74,13 @@ Example:
|
||||
po.ParseFile("/path/to/po/file/translations.po")
|
||||
|
||||
// Get translation
|
||||
println(po.Get("Translate this"))
|
||||
fmt.Println(po.Get("Translate this"))
|
||||
}
|
||||
|
||||
*/
|
||||
type Po struct {
|
||||
// Headers
|
||||
RawHeaders string
|
||||
// Headers storage
|
||||
Headers textproto.MIMEHeader
|
||||
|
||||
// Language header
|
||||
Language string
|
||||
@@ -133,7 +140,6 @@ func (po *Po) ParseFile(f string) {
|
||||
func (po *Po) Parse(str string) {
|
||||
// Lock while parsing
|
||||
po.Lock()
|
||||
defer po.Unlock()
|
||||
|
||||
// Init storage
|
||||
if po.translations == nil {
|
||||
@@ -188,7 +194,7 @@ func (po *Po) Parse(str string) {
|
||||
|
||||
// Multi line strings and headers
|
||||
if strings.HasPrefix(l, "\"") && strings.HasSuffix(l, "\"") {
|
||||
state = po.parseString(l, state)
|
||||
po.parseString(l, state)
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -196,6 +202,9 @@ func (po *Po) Parse(str string) {
|
||||
// Save last translation buffer.
|
||||
po.saveBuffer()
|
||||
|
||||
// Unlock to parse headers
|
||||
po.Unlock()
|
||||
|
||||
// Parse headers
|
||||
po.parseHeaders()
|
||||
}
|
||||
@@ -203,23 +212,24 @@ func (po *Po) Parse(str string) {
|
||||
// saveBuffer takes the context and translation buffers
|
||||
// and saves it on the translations collection
|
||||
func (po *Po) saveBuffer() {
|
||||
// If we have something to save...
|
||||
if po.trBuffer.id != "" {
|
||||
// With no context...
|
||||
if po.ctxBuffer == "" {
|
||||
po.translations[po.trBuffer.id] = po.trBuffer
|
||||
} else {
|
||||
// With context...
|
||||
if _, ok := po.contexts[po.ctxBuffer]; !ok {
|
||||
po.contexts[po.ctxBuffer] = make(map[string]*translation)
|
||||
}
|
||||
po.contexts[po.ctxBuffer][po.trBuffer.id] = po.trBuffer
|
||||
// With no context...
|
||||
if po.ctxBuffer == "" {
|
||||
po.translations[po.trBuffer.id] = po.trBuffer
|
||||
} else {
|
||||
// With context...
|
||||
if _, ok := po.contexts[po.ctxBuffer]; !ok {
|
||||
po.contexts[po.ctxBuffer] = make(map[string]*translation)
|
||||
}
|
||||
po.contexts[po.ctxBuffer][po.trBuffer.id] = po.trBuffer
|
||||
|
||||
// Flush buffer
|
||||
po.trBuffer = newTranslation()
|
||||
po.ctxBuffer = ""
|
||||
// Cleanup current context buffer if needed
|
||||
if po.trBuffer.id != "" {
|
||||
po.ctxBuffer = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Flush translation buffer
|
||||
po.trBuffer = newTranslation()
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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 {
|
||||
case msgStr:
|
||||
// Check for multiline from previously set msgid
|
||||
if po.trBuffer.id != "" {
|
||||
// Append to last translation found
|
||||
uq, _ := strconv.Unquote(l)
|
||||
po.trBuffer.trs[len(po.trBuffer.trs)-1] += uq
|
||||
// Append to last translation found
|
||||
po.trBuffer.trs[len(po.trBuffer.trs)-1] += clean
|
||||
|
||||
}
|
||||
case msgID:
|
||||
// Multiline msgid - Append to current id
|
||||
uq, _ := strconv.Unquote(l)
|
||||
po.trBuffer.id += uq
|
||||
po.trBuffer.id += clean
|
||||
|
||||
case msgIDPlural:
|
||||
// Multiline msgid - Append to current id
|
||||
uq, _ := strconv.Unquote(l)
|
||||
po.trBuffer.pluralID += uq
|
||||
po.trBuffer.pluralID += clean
|
||||
|
||||
case msgCtxt:
|
||||
// Multiline context - Append to current context
|
||||
ctxt, _ := strconv.Unquote(l)
|
||||
po.ctxBuffer += ctxt
|
||||
default:
|
||||
// Otherwise is a header
|
||||
h, _ := strconv.Unquote(strings.TrimSpace(l))
|
||||
po.RawHeaders += h
|
||||
return head
|
||||
}
|
||||
po.ctxBuffer += clean
|
||||
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
// isValidLine checks for line prefixes to detect valid syntax.
|
||||
func (po *Po) isValidLine(l string) bool {
|
||||
// Skip empty lines
|
||||
if l == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check prefix
|
||||
if !strings.HasPrefix(l, "\"") && !strings.HasPrefix(l, "msgctxt") && !strings.HasPrefix(l, "msgid") && !strings.HasPrefix(l, "msgid_plural") && !strings.HasPrefix(l, "msgstr") {
|
||||
return false
|
||||
valid := []string{
|
||||
"\"",
|
||||
"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
|
||||
func (po *Po) parseHeaders() {
|
||||
// Make sure we end with 2 carriage returns.
|
||||
po.RawHeaders += "\n\n"
|
||||
raw := po.Get("") + "\n\n"
|
||||
|
||||
// Read
|
||||
reader := bufio.NewReader(strings.NewReader(po.RawHeaders))
|
||||
reader := bufio.NewReader(strings.NewReader(raw))
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
||||
// Get/save needed headers
|
||||
po.Language = mimeHeader.Get("Language")
|
||||
po.PluralForms = mimeHeader.Get("Plural-Forms")
|
||||
po.Language = po.Headers.Get("Language")
|
||||
po.PluralForms = po.Headers.Get("Plural-Forms")
|
||||
|
||||
// Parse Plural-Forms formula
|
||||
if po.PluralForms == "" {
|
||||
@@ -415,12 +427,12 @@ func (po *Po) Get(str string, vars ...interface{}) string {
|
||||
|
||||
if po.translations != nil {
|
||||
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 fmt.Sprintf(str, vars...)
|
||||
return printf(str, vars...)
|
||||
}
|
||||
|
||||
// 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 _, 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 {
|
||||
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.
|
||||
@@ -453,14 +465,14 @@ func (po *Po) GetC(str, ctx string, vars ...interface{}) string {
|
||||
if _, ok := po.contexts[ctx]; ok {
|
||||
if po.contexts[ctx] != nil {
|
||||
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 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.
|
||||
@@ -474,14 +486,14 @@ func (po *Po) GetNC(str, plural string, n int, ctx string, vars ...interface{})
|
||||
if _, ok := po.contexts[ctx]; ok {
|
||||
if po.contexts[ctx] != nil {
|
||||
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 {
|
||||
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) {
|
||||
// Set PO content
|
||||
str := `
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
# Initial comment
|
||||
# Headers below
|
||||
"Language: en\n"
|
||||
@@ -48,14 +51,6 @@ msgstr[0] "This one is the singular: %s"
|
||||
msgstr[1] "This one is the plural: %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"
|
||||
msgid "One with var: %s"
|
||||
msgid_plural "Several with vars: %s"
|
||||
@@ -75,11 +70,11 @@ msgstr ""
|
||||
msgid "Empty plural form singular"
|
||||
msgid_plural "Empty plural form"
|
||||
msgstr[0] "Singular translated"
|
||||
msgstr[1] "
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "More"
|
||||
msgstr "More translation"
|
||||
"
|
||||
|
||||
`
|
||||
|
||||
// Write PO content to file
|
||||
@@ -152,17 +147,6 @@ msgstr "More translation"
|
||||
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
|
||||
v = "Test"
|
||||
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) {
|
||||
// Set PO content
|
||||
str := `
|
||||
msgid ""
|
||||
msgstr ""
|
||||
# Initial comment
|
||||
# Headers below
|
||||
"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) {
|
||||
// Single form
|
||||
str := `
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Plural-Forms: nplurals=1; plural=0;"
|
||||
|
||||
# Some comment
|
||||
@@ -292,6 +330,8 @@ msgstr[3] "Plural form 3"
|
||||
func TestPluralForms2(t *testing.T) {
|
||||
// 2 forms
|
||||
str := `
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;"
|
||||
|
||||
# Some comment
|
||||
@@ -331,6 +371,8 @@ msgstr[3] "Plural form 3"
|
||||
func TestPluralForms3(t *testing.T) {
|
||||
// 3 forms
|
||||
str := `
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;"
|
||||
|
||||
# Some comment
|
||||
@@ -378,6 +420,8 @@ msgstr[3] "Plural form 3"
|
||||
func TestPluralFormsSpecial(t *testing.T) {
|
||||
// 3 forms special
|
||||
str := `
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Plural-Forms: nplurals=3;"
|
||||
"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
|
||||
}
|
||||
|
||||
// CallExpr provide calling expression.
|
||||
type CallExpr struct {
|
||||
ExprImpl
|
||||
Func interface{}
|
||||
Name string
|
||||
SubExprs []Expr
|
||||
}
|
||||
|
||||
// ParenExpr provide parent block expression.
|
||||
type ParenExpr struct {
|
||||
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"
|
||||
)
|
||||
|
||||
//line parser.go.y:15
|
||||
//line parser.go.y:16
|
||||
type yySymType struct {
|
||||
yys int
|
||||
compstmt []ast.Stmt
|
||||
stmts []ast.Stmt
|
||||
stmt ast.Stmt
|
||||
expr ast.Expr
|
||||
exprs []ast.Expr
|
||||
tok ast.Token
|
||||
term ast.Token
|
||||
terms ast.Token
|
||||
@@ -82,106 +83,107 @@ const yyEofCode = 1
|
||||
const yyErrCode = 2
|
||||
const yyInitialStackSize = 16
|
||||
|
||||
//line parser.go.y:194
|
||||
//line parser.go.y:213
|
||||
|
||||
//line yacctab:1
|
||||
var yyExca = [...]int{
|
||||
-1, 1,
|
||||
1, -1,
|
||||
-2, 0,
|
||||
-1, 49,
|
||||
-1, 50,
|
||||
7, 0,
|
||||
8, 0,
|
||||
-2, 20,
|
||||
-1, 50,
|
||||
-1, 51,
|
||||
7, 0,
|
||||
8, 0,
|
||||
-2, 21,
|
||||
}
|
||||
|
||||
const yyNprod = 36
|
||||
const yyNprod = 40
|
||||
const yyPrivate = 57344
|
||||
|
||||
var yyTokenNames []string
|
||||
var yyStates []string
|
||||
|
||||
const yyLast = 249
|
||||
const yyLast = 251
|
||||
|
||||
var yyAct = [...]int{
|
||||
|
||||
9, 6, 7, 33, 35, 4, 22, 23, 3, 18,
|
||||
24, 25, 26, 37, 38, 39, 2, 40, 33, 35,
|
||||
17, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
||||
51, 52, 53, 54, 55, 56, 57, 58, 27, 28,
|
||||
30, 32, 34, 36, 8, 1, 21, 60, 0, 29,
|
||||
9, 6, 7, 33, 35, 37, 22, 23, 60, 3,
|
||||
24, 25, 26, 38, 39, 40, 1, 41, 33, 35,
|
||||
8, 43, 44, 45, 46, 47, 48, 49, 50, 51,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 61, 42,
|
||||
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,
|
||||
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,
|
||||
0, 0, 22, 23, 0, 0, 24, 25, 26, 0,
|
||||
0, 0, 0, 59, 33, 35, 27, 28, 30, 32,
|
||||
34, 36, 0, 20, 21, 0, 0, 29, 31, 0,
|
||||
0, 22, 23, 0, 0, 24, 25, 26, 0, 0,
|
||||
0, 0, 0, 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, 0, 33, 35, 27, 28, 30, 32, 0, 36,
|
||||
0, 0, 0, 0, 0, 29, 31, 0, 0, 22,
|
||||
23, 0, 0, 24, 25, 26, 27, 28, 30, 32,
|
||||
0, 33, 35, 0, 0, 0, 0, 29, 31, 0,
|
||||
0, 22, 23, 0, 0, 24, 25, 26, 30, 32,
|
||||
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,
|
||||
0, 0, 0, 0, 33, 35, 27, 28, 30, 32,
|
||||
0, 36, 0, 0, 0, 0, 0, 29, 31, 0,
|
||||
0, 22, 23, 0, 0, 24, 25, 26, 27, 28,
|
||||
30, 32, 0, 33, 35, 0, 0, 0, 0, 29,
|
||||
31, 0, 0, 22, 23, 0, 0, 24, 25, 26,
|
||||
30, 32, 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{
|
||||
|
||||
-35, -1000, 216, -35, -35, -1000, -1000, -1000, -1000, 89,
|
||||
-1000, -1000, 216, 216, 216, -1000, 216, -1000, 196, -1000,
|
||||
216, 216, 216, 216, 216, 216, 216, 216, 216, 216,
|
||||
216, 216, 216, 216, 216, 216, 216, -31, -31, -31,
|
||||
60, -1000, 118, 31, 203, 203, -31, -31, -31, 189,
|
||||
189, -16, -16, -16, -16, 118, 147, 118, 169, -1000,
|
||||
216, 118,
|
||||
-35, -1000, 218, -35, -35, -1000, -1000, -1000, -1000, 91,
|
||||
-27, -1000, 218, 218, 218, -1000, 218, -1000, 198, -1000,
|
||||
218, 218, 218, 218, 218, 218, 218, 218, 218, 218,
|
||||
218, 218, 218, 218, 218, 218, 218, 218, -31, -31,
|
||||
-31, 62, -1000, 120, 33, 205, 205, -31, -31, -31,
|
||||
191, 191, -16, -16, -16, -16, 120, 149, 120, 171,
|
||||
29, 120, -1000, 218, -1000, 218, 120, 120,
|
||||
}
|
||||
var yyPgo = [...]int{
|
||||
|
||||
0, 45, 8, 44, 0, 16, 5, 55,
|
||||
0, 16, 9, 20, 0, 8, 53, 50, 115,
|
||||
}
|
||||
var yyR1 = [...]int{
|
||||
|
||||
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,
|
||||
5, 5, 6, 6, 7, 7,
|
||||
4, 5, 5, 5, 6, 6, 7, 7, 8, 8,
|
||||
}
|
||||
var yyR2 = [...]int{
|
||||
|
||||
0, 1, 2, 2, 3, 3, 1, 1, 1, 2,
|
||||
2, 2, 1, 5, 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{
|
||||
|
||||
-1000, -1, -5, -2, -6, -7, 36, 37, -3, -4,
|
||||
4, 5, 23, 30, 31, 6, 32, -5, -6, -7,
|
||||
-1000, -1, -6, -2, -7, -8, 36, 37, -3, -4,
|
||||
4, 5, 23, 30, 31, 6, 32, -6, -7, -8,
|
||||
14, 15, 22, 23, 26, 27, 28, 7, 8, 18,
|
||||
9, 19, 10, 34, 11, 35, 12, -4, -4, -4,
|
||||
-4, -3, -4, -4, -4, -4, -4, -4, -4, -4,
|
||||
-4, -4, -4, -4, -4, -4, -4, -4, -4, 33,
|
||||
16, -4,
|
||||
9, 19, 10, 34, 11, 35, 12, 32, -4, -4,
|
||||
-4, -4, -3, -4, -4, -4, -4, -4, -4, -4,
|
||||
-4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
|
||||
-5, -4, 33, 16, 33, 17, -4, -4,
|
||||
}
|
||||
var yyDef = [...]int{
|
||||
|
||||
30, -2, 1, 30, 31, 32, 34, 35, 3, 6,
|
||||
7, 8, 0, 0, 0, 12, 0, 2, 31, 33,
|
||||
34, -2, 1, 34, 35, 36, 38, 39, 3, 6,
|
||||
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, 9, 10, 11,
|
||||
0, 4, 5, 0, 15, 16, 17, 18, 19, -2,
|
||||
-2, 22, 23, 24, 25, 26, 27, 28, 29, 14,
|
||||
0, 13,
|
||||
0, 0, 0, 0, 0, 0, 0, 31, 9, 10,
|
||||
11, 0, 4, 5, 0, 15, 16, 17, 18, 19,
|
||||
-2, -2, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
0, 32, 14, 0, 30, 0, 13, 33,
|
||||
}
|
||||
var yyTok1 = [...]int{
|
||||
|
||||
@@ -547,19 +549,19 @@ yydefault:
|
||||
|
||||
case 1:
|
||||
yyDollar = yyS[yypt-1 : yypt+1]
|
||||
//line parser.go.y:43
|
||||
//line parser.go.y:45
|
||||
{
|
||||
yyVAL.compstmt = nil
|
||||
}
|
||||
case 2:
|
||||
yyDollar = yyS[yypt-2 : yypt+1]
|
||||
//line parser.go.y:47
|
||||
//line parser.go.y:49
|
||||
{
|
||||
yyVAL.compstmt = yyDollar[1].stmts
|
||||
}
|
||||
case 3:
|
||||
yyDollar = yyS[yypt-2 : yypt+1]
|
||||
//line parser.go.y:53
|
||||
//line parser.go.y:55
|
||||
{
|
||||
yyVAL.stmts = []ast.Stmt{yyDollar[2].stmt}
|
||||
if l, ok := yylex.(*Lexer); ok {
|
||||
@@ -568,7 +570,7 @@ yydefault:
|
||||
}
|
||||
case 4:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line parser.go.y:60
|
||||
//line parser.go.y:62
|
||||
{
|
||||
if yyDollar[3].stmt != nil {
|
||||
yyVAL.stmts = append(yyDollar[1].stmts, yyDollar[3].stmt)
|
||||
@@ -579,172 +581,196 @@ yydefault:
|
||||
}
|
||||
case 5:
|
||||
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}
|
||||
}
|
||||
case 6:
|
||||
yyDollar = yyS[yypt-1 : yypt+1]
|
||||
//line parser.go.y:75
|
||||
//line parser.go.y:77
|
||||
{
|
||||
yyVAL.stmt = &ast.ExprStmt{Expr: yyDollar[1].expr}
|
||||
}
|
||||
case 7:
|
||||
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}
|
||||
}
|
||||
case 8:
|
||||
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}
|
||||
}
|
||||
case 9:
|
||||
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}
|
||||
}
|
||||
case 10:
|
||||
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}
|
||||
}
|
||||
case 11:
|
||||
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}
|
||||
}
|
||||
case 12:
|
||||
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}
|
||||
}
|
||||
case 13:
|
||||
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}
|
||||
}
|
||||
case 14:
|
||||
yyDollar = yyS[yypt-3 : yypt+1]
|
||||
//line parser.go.y:109
|
||||
//line parser.go.y:111
|
||||
{
|
||||
yyVAL.expr = &ast.ParenExpr{SubExpr: yyDollar[2].expr}
|
||||
}
|
||||
case 15:
|
||||
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}
|
||||
}
|
||||
case 16:
|
||||
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}
|
||||
}
|
||||
case 17:
|
||||
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}
|
||||
}
|
||||
case 18:
|
||||
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}
|
||||
}
|
||||
case 19:
|
||||
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}
|
||||
}
|
||||
case 20:
|
||||
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}
|
||||
}
|
||||
case 21:
|
||||
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}
|
||||
}
|
||||
case 22:
|
||||
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}
|
||||
}
|
||||
case 23:
|
||||
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}
|
||||
}
|
||||
case 24:
|
||||
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}
|
||||
}
|
||||
case 25:
|
||||
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}
|
||||
}
|
||||
case 26:
|
||||
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}
|
||||
}
|
||||
case 27:
|
||||
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}
|
||||
}
|
||||
case 28:
|
||||
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}
|
||||
}
|
||||
case 29:
|
||||
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}
|
||||
}
|
||||
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:
|
||||
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:
|
||||
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]
|
||||
//line parser.go.y:182
|
||||
//line parser.go.y:201
|
||||
{
|
||||
}
|
||||
case 34:
|
||||
case 38:
|
||||
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]
|
||||
//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<stmt> stmt
|
||||
%type<expr> expr
|
||||
%type<exprs> exprs
|
||||
|
||||
%union{
|
||||
compstmt []ast.Stmt
|
||||
stmts []ast.Stmt
|
||||
stmt ast.Stmt
|
||||
expr ast.Expr
|
||||
exprs []ast.Expr
|
||||
tok ast.Token
|
||||
term ast.Token
|
||||
terms ast.Token
|
||||
@@ -169,6 +171,23 @@ expr :
|
||||
{
|
||||
$$ = &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 */
|
||||
| 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
|
||||
$accept: .compstmt $end
|
||||
opt_terms: . (30)
|
||||
opt_terms: . (34)
|
||||
|
||||
';' shift 6
|
||||
'\n' shift 7
|
||||
. reduce 30 (src line 173)
|
||||
. reduce 34 (src line 192)
|
||||
|
||||
compstmt goto 1
|
||||
stmts goto 3
|
||||
@@ -31,7 +31,7 @@ state 2
|
||||
'!' shift 13
|
||||
'^' shift 14
|
||||
'(' shift 16
|
||||
. reduce 1 (src line 42)
|
||||
. reduce 1 (src line 44)
|
||||
|
||||
stmt goto 8
|
||||
expr goto 9
|
||||
@@ -39,48 +39,48 @@ state 2
|
||||
state 3
|
||||
compstmt: stmts.opt_terms
|
||||
stmts: stmts.terms stmt
|
||||
opt_terms: . (30)
|
||||
opt_terms: . (34)
|
||||
|
||||
';' shift 6
|
||||
'\n' shift 7
|
||||
. reduce 30 (src line 173)
|
||||
. reduce 34 (src line 192)
|
||||
|
||||
opt_terms goto 17
|
||||
terms goto 18
|
||||
term goto 5
|
||||
|
||||
state 4
|
||||
opt_terms: terms. (31)
|
||||
opt_terms: terms. (35)
|
||||
terms: terms.term
|
||||
|
||||
';' shift 6
|
||||
'\n' shift 7
|
||||
. reduce 31 (src line 174)
|
||||
. reduce 35 (src line 193)
|
||||
|
||||
term goto 19
|
||||
|
||||
state 5
|
||||
terms: term. (32)
|
||||
terms: term. (36)
|
||||
|
||||
. reduce 32 (src line 178)
|
||||
. reduce 36 (src line 197)
|
||||
|
||||
|
||||
state 6
|
||||
term: ';'. (34)
|
||||
term: ';'. (38)
|
||||
|
||||
. reduce 34 (src line 186)
|
||||
. reduce 38 (src line 205)
|
||||
|
||||
|
||||
state 7
|
||||
term: '\n'. (35)
|
||||
term: '\n'. (39)
|
||||
|
||||
. reduce 35 (src line 189)
|
||||
. reduce 39 (src line 208)
|
||||
|
||||
|
||||
state 8
|
||||
stmts: opt_terms stmt. (3)
|
||||
|
||||
. reduce 3 (src line 51)
|
||||
. reduce 3 (src line 53)
|
||||
|
||||
|
||||
state 9
|
||||
@@ -120,19 +120,21 @@ state 9
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 6 (src line 74)
|
||||
. reduce 6 (src line 76)
|
||||
|
||||
|
||||
state 10
|
||||
expr: IDENT. (7)
|
||||
expr: IDENT.'(' exprs ')'
|
||||
|
||||
. reduce 7 (src line 79)
|
||||
'(' shift 37
|
||||
. reduce 7 (src line 81)
|
||||
|
||||
|
||||
state 11
|
||||
expr: NUMBER. (8)
|
||||
|
||||
. reduce 8 (src line 84)
|
||||
. reduce 8 (src line 86)
|
||||
|
||||
|
||||
state 12
|
||||
@@ -147,7 +149,7 @@ state 12
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 37
|
||||
expr goto 38
|
||||
|
||||
state 13
|
||||
expr: '!'.expr
|
||||
@@ -161,7 +163,7 @@ state 13
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 38
|
||||
expr goto 39
|
||||
|
||||
state 14
|
||||
expr: '^'.expr
|
||||
@@ -175,12 +177,12 @@ state 14
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 39
|
||||
expr goto 40
|
||||
|
||||
state 15
|
||||
expr: STRING. (12)
|
||||
|
||||
. reduce 12 (src line 100)
|
||||
. reduce 12 (src line 102)
|
||||
|
||||
|
||||
state 16
|
||||
@@ -195,17 +197,17 @@ state 16
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 40
|
||||
expr goto 41
|
||||
|
||||
state 17
|
||||
compstmt: stmts opt_terms. (2)
|
||||
|
||||
. reduce 2 (src line 46)
|
||||
. reduce 2 (src line 48)
|
||||
|
||||
|
||||
state 18
|
||||
stmts: stmts terms.stmt
|
||||
opt_terms: terms. (31)
|
||||
opt_terms: terms. (35)
|
||||
terms: terms.term
|
||||
|
||||
IDENT shift 10
|
||||
@@ -217,16 +219,16 @@ state 18
|
||||
'(' shift 16
|
||||
';' shift 6
|
||||
'\n' shift 7
|
||||
. reduce 31 (src line 174)
|
||||
. reduce 35 (src line 193)
|
||||
|
||||
stmt goto 41
|
||||
stmt goto 42
|
||||
expr goto 9
|
||||
term goto 19
|
||||
|
||||
state 19
|
||||
terms: terms term. (33)
|
||||
terms: terms term. (37)
|
||||
|
||||
. reduce 33 (src line 181)
|
||||
. reduce 37 (src line 200)
|
||||
|
||||
|
||||
state 20
|
||||
@@ -241,7 +243,7 @@ state 20
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 42
|
||||
expr goto 43
|
||||
|
||||
state 21
|
||||
expr: expr '?'.expr ':' expr
|
||||
@@ -255,7 +257,7 @@ state 21
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 43
|
||||
expr goto 44
|
||||
|
||||
state 22
|
||||
expr: expr '+'.expr
|
||||
@@ -269,7 +271,7 @@ state 22
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 44
|
||||
expr goto 45
|
||||
|
||||
state 23
|
||||
expr: expr '-'.expr
|
||||
@@ -283,7 +285,7 @@ state 23
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 45
|
||||
expr goto 46
|
||||
|
||||
state 24
|
||||
expr: expr '*'.expr
|
||||
@@ -297,7 +299,7 @@ state 24
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 46
|
||||
expr goto 47
|
||||
|
||||
state 25
|
||||
expr: expr '/'.expr
|
||||
@@ -311,7 +313,7 @@ state 25
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 47
|
||||
expr goto 48
|
||||
|
||||
state 26
|
||||
expr: expr '%'.expr
|
||||
@@ -325,7 +327,7 @@ state 26
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 48
|
||||
expr goto 49
|
||||
|
||||
state 27
|
||||
expr: expr EQEQ.expr
|
||||
@@ -339,7 +341,7 @@ state 27
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 49
|
||||
expr goto 50
|
||||
|
||||
state 28
|
||||
expr: expr NEQ.expr
|
||||
@@ -353,7 +355,7 @@ state 28
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 50
|
||||
expr goto 51
|
||||
|
||||
state 29
|
||||
expr: expr '>'.expr
|
||||
@@ -367,7 +369,7 @@ state 29
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 51
|
||||
expr goto 52
|
||||
|
||||
state 30
|
||||
expr: expr GE.expr
|
||||
@@ -381,7 +383,7 @@ state 30
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 52
|
||||
expr goto 53
|
||||
|
||||
state 31
|
||||
expr: expr '<'.expr
|
||||
@@ -395,7 +397,7 @@ state 31
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 53
|
||||
expr goto 54
|
||||
|
||||
state 32
|
||||
expr: expr LE.expr
|
||||
@@ -409,7 +411,7 @@ state 32
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 54
|
||||
expr goto 55
|
||||
|
||||
state 33
|
||||
expr: expr '|'.expr
|
||||
@@ -423,7 +425,7 @@ state 33
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 55
|
||||
expr goto 56
|
||||
|
||||
state 34
|
||||
expr: expr OROR.expr
|
||||
@@ -437,7 +439,7 @@ state 34
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 56
|
||||
expr goto 57
|
||||
|
||||
state 35
|
||||
expr: expr '&'.expr
|
||||
@@ -451,7 +453,7 @@ state 35
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 57
|
||||
expr goto 58
|
||||
|
||||
state 36
|
||||
expr: expr ANDAND.expr
|
||||
@@ -465,11 +467,27 @@ state 36
|
||||
'(' shift 16
|
||||
. 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
|
||||
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.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
@@ -490,12 +508,12 @@ state 37
|
||||
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 9 (src line 88)
|
||||
. reduce 9 (src line 90)
|
||||
|
||||
|
||||
38: shift/reduce conflict (shift 33(0), red'n 10(10)) on '|'
|
||||
38: shift/reduce conflict (shift 35(0), red'n 10(10)) on '&'
|
||||
state 38
|
||||
39: shift/reduce conflict (shift 33(0), red'n 10(10)) on '|'
|
||||
39: shift/reduce conflict (shift 35(0), red'n 10(10)) on '&'
|
||||
state 39
|
||||
expr: '!' expr. (10)
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
@@ -516,12 +534,12 @@ state 38
|
||||
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 10 (src line 92)
|
||||
. reduce 10 (src line 94)
|
||||
|
||||
|
||||
39: shift/reduce conflict (shift 33(0), red'n 11(10)) on '|'
|
||||
39: shift/reduce conflict (shift 35(0), red'n 11(10)) on '&'
|
||||
state 39
|
||||
40: shift/reduce conflict (shift 33(0), red'n 11(10)) on '|'
|
||||
40: shift/reduce conflict (shift 35(0), red'n 11(10)) on '&'
|
||||
state 40
|
||||
expr: '^' expr. (11)
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
@@ -542,10 +560,10 @@ state 39
|
||||
|
||||
'|' shift 33
|
||||
'&' 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
|
||||
@@ -578,19 +596,19 @@ state 40
|
||||
'*' shift 24
|
||||
'/' shift 25
|
||||
'%' shift 26
|
||||
')' shift 59
|
||||
')' shift 62
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. error
|
||||
|
||||
|
||||
state 41
|
||||
state 42
|
||||
stmts: stmts terms stmt. (4)
|
||||
|
||||
. reduce 4 (src line 59)
|
||||
. reduce 4 (src line 61)
|
||||
|
||||
|
||||
state 42
|
||||
state 43
|
||||
stmt: expr '=' expr. (5)
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
@@ -625,10 +643,10 @@ state 42
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' 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
|
||||
@@ -654,7 +672,7 @@ state 43
|
||||
OROR shift 34
|
||||
ANDAND shift 36
|
||||
'?' shift 21
|
||||
':' shift 60
|
||||
':' shift 63
|
||||
'>' shift 29
|
||||
'<' shift 31
|
||||
'+' shift 22
|
||||
@@ -667,9 +685,9 @@ state 43
|
||||
. error
|
||||
|
||||
|
||||
44: shift/reduce conflict (shift 33(0), red'n 15(8)) on '|'
|
||||
44: shift/reduce conflict (shift 35(0), red'n 15(8)) on '&'
|
||||
state 44
|
||||
45: shift/reduce conflict (shift 33(0), red'n 15(8)) on '|'
|
||||
45: shift/reduce conflict (shift 35(0), red'n 15(8)) on '&'
|
||||
state 45
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr '+' expr. (15)
|
||||
@@ -693,12 +711,12 @@ state 44
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 15 (src line 112)
|
||||
. reduce 15 (src line 114)
|
||||
|
||||
|
||||
45: shift/reduce conflict (shift 33(0), red'n 16(8)) on '|'
|
||||
45: shift/reduce conflict (shift 35(0), red'n 16(8)) on '&'
|
||||
state 45
|
||||
46: shift/reduce conflict (shift 33(0), red'n 16(8)) on '|'
|
||||
46: shift/reduce conflict (shift 35(0), red'n 16(8)) on '&'
|
||||
state 46
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -722,12 +740,12 @@ state 45
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 16 (src line 116)
|
||||
. reduce 16 (src line 118)
|
||||
|
||||
|
||||
46: shift/reduce conflict (shift 33(0), red'n 17(9)) on '|'
|
||||
46: shift/reduce conflict (shift 35(0), red'n 17(9)) on '&'
|
||||
state 46
|
||||
47: shift/reduce conflict (shift 33(0), red'n 17(9)) on '|'
|
||||
47: shift/reduce conflict (shift 35(0), red'n 17(9)) on '&'
|
||||
state 47
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -748,12 +766,12 @@ state 46
|
||||
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 17 (src line 120)
|
||||
. reduce 17 (src line 122)
|
||||
|
||||
|
||||
47: shift/reduce conflict (shift 33(0), red'n 18(9)) on '|'
|
||||
47: shift/reduce conflict (shift 35(0), red'n 18(9)) on '&'
|
||||
state 47
|
||||
48: shift/reduce conflict (shift 33(0), red'n 18(9)) on '|'
|
||||
48: shift/reduce conflict (shift 35(0), red'n 18(9)) on '&'
|
||||
state 48
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -774,12 +792,12 @@ state 47
|
||||
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 18 (src line 124)
|
||||
. reduce 18 (src line 126)
|
||||
|
||||
|
||||
48: shift/reduce conflict (shift 33(0), red'n 19(9)) on '|'
|
||||
48: shift/reduce conflict (shift 35(0), red'n 19(9)) on '&'
|
||||
state 48
|
||||
49: shift/reduce conflict (shift 33(0), red'n 19(9)) on '|'
|
||||
49: shift/reduce conflict (shift 35(0), red'n 19(9)) on '&'
|
||||
state 49
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -800,12 +818,12 @@ state 48
|
||||
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 19 (src line 128)
|
||||
. reduce 19 (src line 130)
|
||||
|
||||
|
||||
49: shift/reduce conflict (shift 33(0), red'n 20(6)) on '|'
|
||||
49: shift/reduce conflict (shift 35(0), red'n 20(6)) on '&'
|
||||
state 49
|
||||
50: shift/reduce conflict (shift 33(0), red'n 20(6)) on '|'
|
||||
50: shift/reduce conflict (shift 35(0), red'n 20(6)) on '&'
|
||||
state 50
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -837,12 +855,12 @@ state 49
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 20 (src line 132)
|
||||
. reduce 20 (src line 134)
|
||||
|
||||
|
||||
50: shift/reduce conflict (shift 33(0), red'n 21(6)) on '|'
|
||||
50: shift/reduce conflict (shift 35(0), red'n 21(6)) on '&'
|
||||
state 50
|
||||
51: shift/reduce conflict (shift 33(0), red'n 21(6)) on '|'
|
||||
51: shift/reduce conflict (shift 35(0), red'n 21(6)) on '&'
|
||||
state 51
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -874,12 +892,12 @@ state 50
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 21 (src line 136)
|
||||
. reduce 21 (src line 138)
|
||||
|
||||
|
||||
51: shift/reduce conflict (shift 33(0), red'n 22(7)) on '|'
|
||||
51: shift/reduce conflict (shift 35(0), red'n 22(7)) on '&'
|
||||
state 51
|
||||
52: shift/reduce conflict (shift 33(0), red'n 22(7)) on '|'
|
||||
52: shift/reduce conflict (shift 35(0), red'n 22(7)) on '&'
|
||||
state 52
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -905,12 +923,12 @@ state 51
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 22 (src line 140)
|
||||
. reduce 22 (src line 142)
|
||||
|
||||
|
||||
52: shift/reduce conflict (shift 33(0), red'n 23(7)) on '|'
|
||||
52: shift/reduce conflict (shift 35(0), red'n 23(7)) on '&'
|
||||
state 52
|
||||
53: shift/reduce conflict (shift 33(0), red'n 23(7)) on '|'
|
||||
53: shift/reduce conflict (shift 35(0), red'n 23(7)) on '&'
|
||||
state 53
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -936,12 +954,12 @@ state 52
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 23 (src line 144)
|
||||
. reduce 23 (src line 146)
|
||||
|
||||
|
||||
53: shift/reduce conflict (shift 33(0), red'n 24(7)) on '|'
|
||||
53: shift/reduce conflict (shift 35(0), red'n 24(7)) on '&'
|
||||
state 53
|
||||
54: shift/reduce conflict (shift 33(0), red'n 24(7)) on '|'
|
||||
54: shift/reduce conflict (shift 35(0), red'n 24(7)) on '&'
|
||||
state 54
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -967,12 +985,12 @@ state 53
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 24 (src line 148)
|
||||
. reduce 24 (src line 150)
|
||||
|
||||
|
||||
54: shift/reduce conflict (shift 33(0), red'n 25(7)) on '|'
|
||||
54: shift/reduce conflict (shift 35(0), red'n 25(7)) on '&'
|
||||
state 54
|
||||
55: shift/reduce conflict (shift 33(0), red'n 25(7)) on '|'
|
||||
55: shift/reduce conflict (shift 35(0), red'n 25(7)) on '&'
|
||||
state 55
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -998,26 +1016,26 @@ state 54
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' 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
|
||||
55: 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
|
||||
55: 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
|
||||
55: shift/reduce conflict (shift 36(4), red'n 26(0)) on ANDAND
|
||||
55: shift/reduce conflict (shift 21(2), red'n 26(0)) on '?'
|
||||
55: shift/reduce conflict (shift 29(7), red'n 26(0)) on '>'
|
||||
55: shift/reduce conflict (shift 31(7), red'n 26(0)) on '<'
|
||||
55: shift/reduce conflict (shift 22(8), red'n 26(0)) on '+'
|
||||
55: shift/reduce conflict (shift 23(8), red'n 26(0)) on '-'
|
||||
55: shift/reduce conflict (shift 24(9), red'n 26(0)) on '*'
|
||||
55: shift/reduce conflict (shift 25(9), red'n 26(0)) on '/'
|
||||
55: shift/reduce conflict (shift 26(9), red'n 26(0)) on '%'
|
||||
55: shift/reduce conflict (shift 33(0), red'n 26(0)) on '|'
|
||||
55: shift/reduce conflict (shift 35(0), red'n 26(0)) on '&'
|
||||
state 55
|
||||
56: shift/reduce conflict (shift 27(6), red'n 26(0)) on EQEQ
|
||||
56: shift/reduce conflict (shift 28(6), red'n 26(0)) on NEQ
|
||||
56: shift/reduce conflict (shift 30(7), red'n 26(0)) on GE
|
||||
56: shift/reduce conflict (shift 32(7), red'n 26(0)) on LE
|
||||
56: shift/reduce conflict (shift 34(3), red'n 26(0)) on OROR
|
||||
56: shift/reduce conflict (shift 36(4), red'n 26(0)) on ANDAND
|
||||
56: shift/reduce conflict (shift 21(2), red'n 26(0)) on '?'
|
||||
56: shift/reduce conflict (shift 29(7), red'n 26(0)) on '>'
|
||||
56: shift/reduce conflict (shift 31(7), red'n 26(0)) on '<'
|
||||
56: shift/reduce conflict (shift 22(8), red'n 26(0)) on '+'
|
||||
56: shift/reduce conflict (shift 23(8), red'n 26(0)) on '-'
|
||||
56: shift/reduce conflict (shift 24(9), red'n 26(0)) on '*'
|
||||
56: shift/reduce conflict (shift 25(9), red'n 26(0)) on '/'
|
||||
56: shift/reduce conflict (shift 26(9), red'n 26(0)) on '%'
|
||||
56: shift/reduce conflict (shift 33(0), red'n 26(0)) on '|'
|
||||
56: shift/reduce conflict (shift 35(0), red'n 26(0)) on '&'
|
||||
state 56
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -1052,12 +1070,12 @@ state 55
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 26 (src line 156)
|
||||
. reduce 26 (src line 158)
|
||||
|
||||
|
||||
56: shift/reduce conflict (shift 33(0), red'n 27(3)) on '|'
|
||||
56: shift/reduce conflict (shift 35(0), red'n 27(3)) on '&'
|
||||
state 56
|
||||
57: shift/reduce conflict (shift 33(0), red'n 27(3)) on '|'
|
||||
57: shift/reduce conflict (shift 35(0), red'n 27(3)) on '&'
|
||||
state 57
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -1090,26 +1108,26 @@ state 56
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' 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
|
||||
57: 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
|
||||
57: 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
|
||||
57: shift/reduce conflict (shift 36(4), red'n 28(0)) on ANDAND
|
||||
57: shift/reduce conflict (shift 21(2), red'n 28(0)) on '?'
|
||||
57: shift/reduce conflict (shift 29(7), red'n 28(0)) on '>'
|
||||
57: shift/reduce conflict (shift 31(7), red'n 28(0)) on '<'
|
||||
57: shift/reduce conflict (shift 22(8), red'n 28(0)) on '+'
|
||||
57: shift/reduce conflict (shift 23(8), red'n 28(0)) on '-'
|
||||
57: shift/reduce conflict (shift 24(9), red'n 28(0)) on '*'
|
||||
57: shift/reduce conflict (shift 25(9), red'n 28(0)) on '/'
|
||||
57: shift/reduce conflict (shift 26(9), red'n 28(0)) on '%'
|
||||
57: shift/reduce conflict (shift 33(0), red'n 28(0)) on '|'
|
||||
57: shift/reduce conflict (shift 35(0), red'n 28(0)) on '&'
|
||||
state 57
|
||||
58: shift/reduce conflict (shift 27(6), red'n 28(0)) on EQEQ
|
||||
58: shift/reduce conflict (shift 28(6), red'n 28(0)) on NEQ
|
||||
58: shift/reduce conflict (shift 30(7), red'n 28(0)) on GE
|
||||
58: shift/reduce conflict (shift 32(7), red'n 28(0)) on LE
|
||||
58: shift/reduce conflict (shift 34(3), red'n 28(0)) on OROR
|
||||
58: shift/reduce conflict (shift 36(4), red'n 28(0)) on ANDAND
|
||||
58: shift/reduce conflict (shift 21(2), red'n 28(0)) on '?'
|
||||
58: shift/reduce conflict (shift 29(7), red'n 28(0)) on '>'
|
||||
58: shift/reduce conflict (shift 31(7), red'n 28(0)) on '<'
|
||||
58: shift/reduce conflict (shift 22(8), red'n 28(0)) on '+'
|
||||
58: shift/reduce conflict (shift 23(8), red'n 28(0)) on '-'
|
||||
58: shift/reduce conflict (shift 24(9), red'n 28(0)) on '*'
|
||||
58: shift/reduce conflict (shift 25(9), red'n 28(0)) on '/'
|
||||
58: shift/reduce conflict (shift 26(9), red'n 28(0)) on '%'
|
||||
58: shift/reduce conflict (shift 33(0), red'n 28(0)) on '|'
|
||||
58: shift/reduce conflict (shift 35(0), red'n 28(0)) on '&'
|
||||
state 58
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -1144,12 +1162,12 @@ state 57
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 28 (src line 164)
|
||||
. reduce 28 (src line 166)
|
||||
|
||||
|
||||
58: shift/reduce conflict (shift 33(0), red'n 29(4)) on '|'
|
||||
58: shift/reduce conflict (shift 35(0), red'n 29(4)) on '&'
|
||||
state 58
|
||||
59: shift/reduce conflict (shift 33(0), red'n 29(4)) on '|'
|
||||
59: shift/reduce conflict (shift 35(0), red'n 29(4)) on '&'
|
||||
state 59
|
||||
expr: expr.'?' expr ':' expr
|
||||
expr: expr.'+' expr
|
||||
expr: expr.'-' expr
|
||||
@@ -1181,16 +1199,63 @@ state 58
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 29 (src line 168)
|
||||
|
||||
|
||||
state 59
|
||||
expr: '(' expr ')'. (14)
|
||||
|
||||
. reduce 14 (src line 108)
|
||||
. reduce 29 (src line 170)
|
||||
|
||||
|
||||
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
|
||||
|
||||
IDENT shift 10
|
||||
@@ -1202,11 +1267,31 @@ state 60
|
||||
'(' shift 16
|
||||
. error
|
||||
|
||||
expr goto 61
|
||||
expr goto 66
|
||||
|
||||
61: shift/reduce conflict (shift 33(0), red'n 13(2)) on '|'
|
||||
61: shift/reduce conflict (shift 35(0), red'n 13(2)) on '&'
|
||||
state 61
|
||||
state 64
|
||||
expr: IDENT '(' exprs ')'. (30)
|
||||
|
||||
. 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. (13)
|
||||
expr: expr.'+' expr
|
||||
@@ -1241,18 +1326,56 @@ state 61
|
||||
'%' shift 26
|
||||
'|' shift 33
|
||||
'&' shift 35
|
||||
. reduce 13 (src line 104)
|
||||
. reduce 13 (src line 106)
|
||||
|
||||
|
||||
37 terminals, 8 nonterminals
|
||||
36 grammar rules, 62/8000 states
|
||||
state 67
|
||||
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
|
||||
57 working sets used
|
||||
memory: parser 35/120000
|
||||
46 extra closures
|
||||
390 shift entries, 5 exceptions
|
||||
34 goto entries
|
||||
58 working sets used
|
||||
memory: parser 38/30000
|
||||
49 extra closures
|
||||
439 shift entries, 5 exceptions
|
||||
37 goto entries
|
||||
2 entries saved by goto default
|
||||
Optimizer space used: output 249/120000
|
||||
249 table entries, 78 zero
|
||||
maximum spread: 37, maximum offset: 60
|
||||
Optimizer space used: output 251/30000
|
||||
251 table entries, 74 zero
|
||||
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"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -39,14 +40,6 @@ func (e *Error) Error() string {
|
||||
// Func is function interface to reflect functions internaly.
|
||||
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.
|
||||
func Run(stmts []ast.Stmt, env *Env) (reflect.Value, error) {
|
||||
rv := NilValue
|
||||
@@ -386,6 +379,80 @@ func invokeExpr(expr ast.Expr, env *Env) (reflect.Value, error) {
|
||||
default:
|
||||
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:
|
||||
rv, err := invokeExpr(e.Expr, env)
|
||||
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