5 Commits

Author SHA1 Message Date
Leonel Quinteros
7d86bb66fe Unify fmt.Sprintf behaviour on Po and Locale 2017-11-02 10:21:20 -03:00
Leonel Quinteros
50cdb4e058 Add Go 1.9 to travis builds 2017-10-26 16:27:26 -03:00
Leonel Quinteros
1fc8dec04d Rewrite PO headers parsing and handling. Implement correct GNU gettext headers format. Fix tests. Fixes #10 2017-09-08 18:08:56 -03:00
Leonel Quinteros
1bb93891f4 Fix README examples 2017-09-01 17:15:49 -03:00
Leonel Quinteros
1e28907f7a Replace Godeps with dep 2017-09-01 17:05:40 -03:00
21 changed files with 835 additions and 439 deletions

View File

@@ -4,6 +4,7 @@ go:
- 1.6
- 1.7
- 1.8
- 1.9
- tip
before_install:

18
Godeps/Godeps.json generated
View File

@@ -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
View File

@@ -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
View 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
View 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"

View File

@@ -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
@@ -261,7 +228,7 @@ msgstr "This one sets the var: %s"
`
// Create Po object
po := new(Po)
po := new(gotext.Po)
po.Parse(str)
fmt.Println(po.Get("Translate this"))
@@ -305,7 +272,7 @@ msgstr[1] "This one is the plural: %s"
`
// Create Po object
po := new(Po)
po := new(gotext.Po)
po.Parse(str)
fmt.Println(po.GetN("One with var: %s", "Several with vars: %s", 54, v))

View File

@@ -22,6 +22,8 @@ For quick/simple translations you can use the package level functions directly.
*/
package gotext
import "fmt"
// Global environment variables
var (
// Default domain to look at when no domain is specified. Used by package level functions.
@@ -152,3 +154,12 @@ func GetNDC(dom, str, plural string, n int, ctx string, vars ...interface{}) str
// Return translation
return storage.GetNDC(dom, str, plural, n, ctx, vars...)
}
// 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
}

View File

@@ -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"
@@ -149,8 +144,8 @@ msgstr[1] ""
func TestUntranslated(t *testing.T) {
// Set PO content
str := `
# msgid ""
# msgstr ""
msgid ""
msgstr ""
# Initial comment
# Headers below
"Language: en\n"
@@ -258,22 +253,29 @@ 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
for i := 0; i < 100; i++ {
wg.Add(1)
// Test translations
go func(done chan bool) {
Get("My text")
done <- true
}(c1)
go func(done chan bool) {
Get("My text")
done <- true
}(c2)
go func() {
defer wg.Done()
Get("My text")
GetN("One with var: %s", "Several with vars: %s", 0, "test")
}()
wg.Add(1)
go func() {
defer wg.Done()
Get("My text")
GetN("One with var: %s", "Several with vars: %s", 1, "test")
}()
Get("My text")
GetN("One with var: %s", "Several with vars: %s", 2, "test")
}
wg.Wait()
}

View File

@@ -1,7 +1,6 @@
package gotext
import (
"fmt"
"os"
"path"
"sync"
@@ -138,7 +137,7 @@ 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.
@@ -175,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...)
}

View File

@@ -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"

110
po.go
View File

@@ -2,14 +2,14 @@ package gotext
import (
"bufio"
"fmt"
"github.com/mattn/kinako/vm"
"io/ioutil"
"net/textproto"
"os"
"strconv"
"strings"
"sync"
"github.com/mattn/kinako/vm"
)
type translation struct {
@@ -79,8 +79,8 @@ Example:
*/
type Po struct {
// Headers
RawHeaders string
// Headers storage
Headers textproto.MIMEHeader
// Language header
Language string
@@ -140,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 {
@@ -195,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
}
}
@@ -203,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()
}
@@ -210,8 +212,6 @@ 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
@@ -221,12 +221,15 @@ func (po *Po) saveBuffer() {
po.contexts[po.ctxBuffer] = make(map[string]*translation)
}
po.contexts[po.ctxBuffer][po.trBuffer.id] = po.trBuffer
}
// Flush buffer
po.trBuffer = newTranslation()
// 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",
@@ -286,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
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",
}
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 == "" {
@@ -422,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.
@@ -439,15 +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.
@@ -461,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.
@@ -482,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...)
}

View File

@@ -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
View File

@@ -0,0 +1,37 @@
# kinako
Kinako is small VM written in Go.
![](https://raw.githubusercontent.com/mattn/kinako/master/kinako.png)
(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
View 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)
}

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 KiB

View File

@@ -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
{
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
View 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)
}
}
}