Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
756045ab5e | ||
|
|
2bb9254f26 | ||
|
|
88952938dc | ||
|
|
cabefc2786 | ||
|
|
b8456329aa | ||
|
|
9bcfe68591 | ||
|
|
28bb992796 | ||
|
|
eccb6c7cf3 | ||
|
|
1c611eff63 | ||
|
|
4a52c7709d | ||
|
|
2c51ed2000 | ||
|
|
d52a867157 | ||
|
|
744b85e833 | ||
|
|
ffcea86f47 |
13
.travis.yml
13
.travis.yml
@@ -1,7 +1,16 @@
|
|||||||
language: go
|
language: go
|
||||||
script: go test -v -race ./...
|
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.5
|
|
||||||
- 1.6
|
- 1.6
|
||||||
|
- 1.7
|
||||||
|
- 1.8
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- go get -t -v ./...
|
||||||
|
|
||||||
|
script: go test -v -race -coverprofile=coverage.txt -covermode=atomic .
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
|
|
||||||
|
|||||||
18
Godeps/Godeps.json
generated
18
Godeps/Godeps.json
generated
@@ -1,22 +1,18 @@
|
|||||||
{
|
{
|
||||||
"ImportPath": "github.com/leonelquinteros/gotext",
|
"ImportPath": "github.com/leonelquinteros/gotext",
|
||||||
"GoVersion": "go1.6",
|
"GoVersion": "devel +be9d7f6d87 Fri Jun 16 00:31:25 2017 +0000",
|
||||||
"GodepVersion": "v74",
|
|
||||||
"Packages": [
|
|
||||||
"./..."
|
|
||||||
],
|
|
||||||
"Deps": [
|
"Deps": [
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/mattn/anko/ast",
|
"ImportPath": "github.com/mattn/kinako/ast",
|
||||||
"Rev": "a8c68fa2983e7dd5d3472992b1fbe2f7c44261f0"
|
"Rev": "fbc18625ec69b28ae03b4eea4c349f215840ee09"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/mattn/anko/parser",
|
"ImportPath": "github.com/mattn/kinako/parser",
|
||||||
"Rev": "a8c68fa2983e7dd5d3472992b1fbe2f7c44261f0"
|
"Rev": "fbc18625ec69b28ae03b4eea4c349f215840ee09"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/mattn/anko/vm",
|
"ImportPath": "github.com/mattn/kinako/vm",
|
||||||
"Rev": "a8c68fa2983e7dd5d3472992b1fbe2f7c44261f0"
|
"Rev": "fbc18625ec69b28ae03b4eea4c349f215840ee09"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
[](https://github.com/leonelquinteros/gotext)
|
||||||
|
[](LICENSE)
|
||||||
[](https://godoc.org/github.com/leonelquinteros/gotext)
|
[](https://godoc.org/github.com/leonelquinteros/gotext)
|
||||||
[](https://travis-ci.org/leonelquinteros/gotext)
|
[](https://travis-ci.org/leonelquinteros/gotext)
|
||||||
|
[](https://codecov.io/gh/leonelquinteros/gotext)
|
||||||
[](https://goreportcard.com/report/github.com/leonelquinteros/gotext)
|
[](https://goreportcard.com/report/github.com/leonelquinteros/gotext)
|
||||||
|
|
||||||
# Gotext
|
# Gotext
|
||||||
|
|
||||||
[GNU gettext utilities](https://www.gnu.org/software/gettext) for Go.
|
[GNU gettext utilities](https://www.gnu.org/software/gettext) for Go.
|
||||||
|
|
||||||
Version: [v1.1.1](https://github.com/leonelquinteros/gotext/releases/tag/v1.1.1)
|
|
||||||
|
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ Version: [v1.1.1](https://github.com/leonelquinteros/gotext/releases/tag/v1.1.1)
|
|||||||
- Support for [message contexts](https://www.gnu.org/software/gettext/manual/html_node/Contexts.html).
|
- Support for [message contexts](https://www.gnu.org/software/gettext/manual/html_node/Contexts.html).
|
||||||
- Thread-safe: This package is safe for concurrent use across multiple goroutines.
|
- Thread-safe: This package is safe for concurrent use across multiple goroutines.
|
||||||
- It works with UTF-8 encoding as it's the default for Go language.
|
- It works with UTF-8 encoding as it's the default for Go language.
|
||||||
- Unit tests available. See coverage: https://gocover.io/github.com/leonelquinteros/gotext
|
- Unit tests available.
|
||||||
- Language codes are automatically simplified from the form `en_UK` to `en` if the first isn't available.
|
- Language codes are automatically simplified from the form `en_UK` to `en` if the first isn't available.
|
||||||
- Ready to use inside Go templates.
|
- Ready to use inside Go templates.
|
||||||
|
|
||||||
@@ -262,7 +263,7 @@ PO format supports defining one or more plural forms for the same translation.
|
|||||||
Relying on the PO file headers, a Plural-Forms formula can be set on the translation file
|
Relying on the PO file headers, a Plural-Forms formula can be set on the translation file
|
||||||
as defined in (https://www.gnu.org/savannah-checkouts/gnu/gettext/manual/html_node/Plural-forms.html)
|
as defined in (https://www.gnu.org/savannah-checkouts/gnu/gettext/manual/html_node/Plural-forms.html)
|
||||||
|
|
||||||
Plural formulas are parsed and evaluated using [Anko](https://github.com/mattn/anko)
|
Plural formulas are parsed and evaluated using [Kinako](https://github.com/mattn/kinako)
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/leonelquinteros/gotext"
|
import "github.com/leonelquinteros/gotext"
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ func TestGettersSetters(t *testing.T) {
|
|||||||
func TestPackageFunctions(t *testing.T) {
|
func TestPackageFunctions(t *testing.T) {
|
||||||
// Set PO content
|
// Set PO content
|
||||||
str := `
|
str := `
|
||||||
msgid ""
|
# msgid ""
|
||||||
msgstr ""
|
# msgstr ""
|
||||||
# Initial comment
|
# Initial comment
|
||||||
# Headers below
|
# Headers below
|
||||||
"Language: en\n"
|
"Language: en\n"
|
||||||
@@ -79,7 +79,7 @@ msgstr "Some random translation in a context"
|
|||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr "More translation"
|
msgstr "More translation"
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create Locales directory on default location
|
// Create Locales directory on default location
|
||||||
dirname := path.Clean("/tmp" + string(os.PathSeparator) + "en_US")
|
dirname := path.Clean("/tmp" + string(os.PathSeparator) + "en_US")
|
||||||
@@ -157,7 +157,7 @@ msgstr[0] "This one is the singular: %s"
|
|||||||
msgstr[1] "This one is the plural: %s"
|
msgstr[1] "This one is the plural: %s"
|
||||||
msgstr[2] "And this is the second plural form: %s"
|
msgstr[2] "And this is the second plural form: %s"
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create Locales directory on default location
|
// Create Locales directory on default location
|
||||||
dirname := path.Clean(library + string(os.PathSeparator) + "en_US")
|
dirname := path.Clean(library + string(os.PathSeparator) + "en_US")
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
func TestLocale(t *testing.T) {
|
func TestLocale(t *testing.T) {
|
||||||
// Set PO content
|
// Set PO content
|
||||||
str := `
|
str := `
|
||||||
msgid ""
|
# msgid ""
|
||||||
msgstr ""
|
# msgstr ""
|
||||||
# Initial comment
|
# Initial comment
|
||||||
# Headers below
|
# Headers below
|
||||||
"Language: en\n"
|
"Language: en\n"
|
||||||
@@ -56,7 +56,7 @@ msgstr "Some random translation in a context"
|
|||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr "More translation"
|
msgstr "More translation"
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create Locales directory with simplified language code
|
// Create Locales directory with simplified language code
|
||||||
dirname := path.Join("/tmp", "en", "LC_MESSAGES")
|
dirname := path.Join("/tmp", "en", "LC_MESSAGES")
|
||||||
@@ -176,7 +176,7 @@ msgstr "Some random translation in a context"
|
|||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr "More translation"
|
msgstr "More translation"
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create Locales directory with simplified language code
|
// Create Locales directory with simplified language code
|
||||||
dirname := path.Join("/tmp", "en", "LC_MESSAGES")
|
dirname := path.Join("/tmp", "en", "LC_MESSAGES")
|
||||||
@@ -259,7 +259,7 @@ msgstr[0] "This one is the singular: %s"
|
|||||||
msgstr[1] "This one is the plural: %s"
|
msgstr[1] "This one is the plural: %s"
|
||||||
msgstr[2] "And this is the second plural form: %s"
|
msgstr[2] "And this is the second plural form: %s"
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create Locales directory with simplified language code
|
// Create Locales directory with simplified language code
|
||||||
dirname := path.Join("/tmp", "es")
|
dirname := path.Join("/tmp", "es")
|
||||||
|
|||||||
95
po.go
95
po.go
@@ -3,13 +3,14 @@ package gotext
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/mattn/anko/vm"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/mattn/kinako/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type translation struct {
|
type translation struct {
|
||||||
@@ -28,7 +29,9 @@ func newTranslation() *translation {
|
|||||||
func (t *translation) get() string {
|
func (t *translation) get() string {
|
||||||
// Look for translation index 0
|
// Look for translation index 0
|
||||||
if _, ok := t.trs[0]; ok {
|
if _, ok := t.trs[0]; ok {
|
||||||
return t.trs[0]
|
if t.trs[0] != "" {
|
||||||
|
return t.trs[0]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return unstranlated id by default
|
// Return unstranlated id by default
|
||||||
@@ -38,7 +41,9 @@ func (t *translation) get() string {
|
|||||||
func (t *translation) getN(n int) string {
|
func (t *translation) getN(n int) string {
|
||||||
// Look for translation index
|
// Look for translation index
|
||||||
if _, ok := t.trs[n]; ok {
|
if _, ok := t.trs[n]; ok {
|
||||||
return t.trs[n]
|
if t.trs[n] != "" {
|
||||||
|
return t.trs[n]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return unstranlated plural by default
|
// Return unstranlated plural by default
|
||||||
@@ -52,18 +57,18 @@ And it's safe for concurrent use by multiple goroutines by using the sync packag
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
import "github.com/leonelquinteros/gotext"
|
import "github.com/leonelquinteros/gotext"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Create po object
|
// Create po object
|
||||||
po := new(gotext.Po)
|
po := new(gotext.Po)
|
||||||
|
|
||||||
// Parse .po file
|
// Parse .po file
|
||||||
po.ParseFile("/path/to/po/file/translations.po")
|
po.ParseFile("/path/to/po/file/translations.po")
|
||||||
|
|
||||||
// Get translation
|
// Get translation
|
||||||
println(po.Get("Translate this"))
|
println(po.Get("Translate this"))
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
type Po struct {
|
type Po struct {
|
||||||
@@ -92,6 +97,16 @@ type Po struct {
|
|||||||
ctxBuffer string
|
ctxBuffer string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type parseState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
head parseState = iota
|
||||||
|
msgCtxt
|
||||||
|
msgID
|
||||||
|
msgIDPlural
|
||||||
|
msgStr
|
||||||
|
)
|
||||||
|
|
||||||
// ParseFile tries to read the file by its provided path (f) and parse its content as a .po file.
|
// ParseFile tries to read the file by its provided path (f) and parse its content as a .po file.
|
||||||
func (po *Po) ParseFile(f string) {
|
func (po *Po) ParseFile(f string) {
|
||||||
// Check if file exists
|
// Check if file exists
|
||||||
@@ -133,6 +148,7 @@ func (po *Po) Parse(str string) {
|
|||||||
po.trBuffer = newTranslation()
|
po.trBuffer = newTranslation()
|
||||||
po.ctxBuffer = ""
|
po.ctxBuffer = ""
|
||||||
|
|
||||||
|
state := head
|
||||||
for _, l := range lines {
|
for _, l := range lines {
|
||||||
// Trim spaces
|
// Trim spaces
|
||||||
l = strings.TrimSpace(l)
|
l = strings.TrimSpace(l)
|
||||||
@@ -145,30 +161,34 @@ func (po *Po) Parse(str string) {
|
|||||||
// Buffer context and continue
|
// Buffer context and continue
|
||||||
if strings.HasPrefix(l, "msgctxt") {
|
if strings.HasPrefix(l, "msgctxt") {
|
||||||
po.parseContext(l)
|
po.parseContext(l)
|
||||||
|
state = msgCtxt
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer msgid and continue
|
// Buffer msgid and continue
|
||||||
if strings.HasPrefix(l, "msgid") && !strings.HasPrefix(l, "msgid_plural") {
|
if strings.HasPrefix(l, "msgid") && !strings.HasPrefix(l, "msgid_plural") {
|
||||||
po.parseID(l)
|
po.parseID(l)
|
||||||
|
state = msgID
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for plural form
|
// Check for plural form
|
||||||
if strings.HasPrefix(l, "msgid_plural") {
|
if strings.HasPrefix(l, "msgid_plural") {
|
||||||
po.parsePluralID(l)
|
po.parsePluralID(l)
|
||||||
|
state = msgIDPlural
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save translation
|
// Save translation
|
||||||
if strings.HasPrefix(l, "msgstr") {
|
if strings.HasPrefix(l, "msgstr") {
|
||||||
po.parseMessage(l)
|
po.parseMessage(l)
|
||||||
|
state = msgStr
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multi line strings and headers
|
// Multi line strings and headers
|
||||||
if strings.HasPrefix(l, "\"") && strings.HasSuffix(l, "\"") {
|
if strings.HasPrefix(l, "\"") && strings.HasSuffix(l, "\"") {
|
||||||
po.parseString(l)
|
state = po.parseString(l, state)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,23 +279,36 @@ func (po *Po) parseMessage(l string) {
|
|||||||
|
|
||||||
// parseString takes a well formatted string without prefix
|
// parseString takes a well formatted string without prefix
|
||||||
// and creates headers or attach multi-line strings when corresponding
|
// and creates headers or attach multi-line strings when corresponding
|
||||||
func (po *Po) parseString(l string) {
|
func (po *Po) parseString(l string, state parseState) parseState {
|
||||||
// Check for multiline from previously set msgid
|
switch state {
|
||||||
if po.trBuffer.id != "" {
|
case msgStr:
|
||||||
// Append to last translation found
|
// 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
|
||||||
|
|
||||||
|
}
|
||||||
|
case msgID:
|
||||||
|
// Multiline msgid - Append to current id
|
||||||
uq, _ := strconv.Unquote(l)
|
uq, _ := strconv.Unquote(l)
|
||||||
po.trBuffer.trs[len(po.trBuffer.trs)-1] += uq
|
po.trBuffer.id += uq
|
||||||
|
case msgIDPlural:
|
||||||
return
|
// Multiline msgid - Append to current id
|
||||||
|
uq, _ := strconv.Unquote(l)
|
||||||
|
po.trBuffer.pluralID += uq
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise is a header
|
return state
|
||||||
h, err := strconv.Unquote(strings.TrimSpace(l))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
po.RawHeaders += h
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// isValidLine checks for line prefixes to detect valid syntax.
|
// isValidLine checks for line prefixes to detect valid syntax.
|
||||||
@@ -403,7 +436,9 @@ func (po *Po) GetN(str, plural string, n int, vars ...interface{}) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the plural string we received by default
|
if n == 1 {
|
||||||
|
return fmt.Sprintf(str, vars...)
|
||||||
|
}
|
||||||
return fmt.Sprintf(plural, vars...)
|
return fmt.Sprintf(plural, vars...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,6 +480,8 @@ func (po *Po) GetNC(str, plural string, n int, ctx string, vars ...interface{})
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the plural string we received by default
|
if n == 1 {
|
||||||
|
return fmt.Sprintf(str, vars...)
|
||||||
|
}
|
||||||
return fmt.Sprintf(plural, vars...)
|
return fmt.Sprintf(plural, vars...)
|
||||||
}
|
}
|
||||||
|
|||||||
88
po_test.go
88
po_test.go
@@ -9,8 +9,6 @@ import (
|
|||||||
func TestPo(t *testing.T) {
|
func TestPo(t *testing.T) {
|
||||||
// Set PO content
|
// Set PO content
|
||||||
str := `
|
str := `
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
# Initial comment
|
# Initial comment
|
||||||
# Headers below
|
# Headers below
|
||||||
"Language: en\n"
|
"Language: en\n"
|
||||||
@@ -26,6 +24,19 @@ msgstr "Translated text"
|
|||||||
msgid "Another string"
|
msgid "Another string"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
# Multi-line msgid
|
||||||
|
msgid "multi"
|
||||||
|
"line"
|
||||||
|
"id"
|
||||||
|
msgstr "id with multiline content"
|
||||||
|
|
||||||
|
# Multi-line msgid_plural
|
||||||
|
msgid "multi"
|
||||||
|
"line"
|
||||||
|
"plural"
|
||||||
|
"id"
|
||||||
|
msgstr "plural id with multiline content"
|
||||||
|
|
||||||
#Multi-line string
|
#Multi-line string
|
||||||
msgid "Multi-line"
|
msgid "Multi-line"
|
||||||
msgstr "Multi "
|
msgstr "Multi "
|
||||||
@@ -58,9 +69,18 @@ msgctxt "Ctx"
|
|||||||
msgid "Some random in a context"
|
msgid "Some random in a context"
|
||||||
msgstr "Some random translation in a context"
|
msgstr "Some random translation in a context"
|
||||||
|
|
||||||
|
msgid "Empty translation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Empty plural form singular"
|
||||||
|
msgid_plural "Empty plural form"
|
||||||
|
msgstr[0] "Singular translated"
|
||||||
|
msgstr[1] "
|
||||||
|
|
||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr "More translation"
|
msgstr "More translation"
|
||||||
`
|
"
|
||||||
|
`
|
||||||
|
|
||||||
// Write PO content to file
|
// Write PO content to file
|
||||||
filename := path.Clean(os.TempDir() + string(os.PathSeparator) + "default.po")
|
filename := path.Clean(os.TempDir() + string(os.PathSeparator) + "default.po")
|
||||||
@@ -97,6 +117,18 @@ msgstr "More translation"
|
|||||||
t.Errorf("Expected 'This one is the singular: Variable' but got '%s'", tr)
|
t.Errorf("Expected 'This one is the singular: Variable' but got '%s'", tr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test multi-line id
|
||||||
|
tr = po.Get("multilineid")
|
||||||
|
if tr != "id with multiline content" {
|
||||||
|
t.Errorf("Expected 'id with multiline content' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test multi-line plural id
|
||||||
|
tr = po.Get("multilinepluralid")
|
||||||
|
if tr != "plural id with multiline content" {
|
||||||
|
t.Errorf("Expected 'plural id with multiline content' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
|
||||||
// Test multi-line
|
// Test multi-line
|
||||||
tr = po.Get("Multi-line")
|
tr = po.Get("Multi-line")
|
||||||
if tr != "Multi line" {
|
if tr != "Multi line" {
|
||||||
@@ -122,8 +154,8 @@ msgstr "More translation"
|
|||||||
|
|
||||||
// Test syntax error parsed translations
|
// Test syntax error parsed translations
|
||||||
tr = po.Get("This one has invalid syntax translations")
|
tr = po.Get("This one has invalid syntax translations")
|
||||||
if tr != "" {
|
if tr != "This one has invalid syntax translations" {
|
||||||
t.Errorf("Expected '' but got '%s'", tr)
|
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)
|
tr = po.GetN("This one has invalid syntax translations", "This are tests", 4)
|
||||||
@@ -144,19 +176,47 @@ msgstr "More translation"
|
|||||||
t.Errorf("Expected 'This one is the plural in a Ctx context: Test' but got '%s'", tr)
|
t.Errorf("Expected 'This one is the plural in a Ctx context: Test' but got '%s'", tr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test default plural vs singular return responses
|
||||||
|
tr = po.GetN("Original", "Original plural", 4)
|
||||||
|
if tr != "Original plural" {
|
||||||
|
t.Errorf("Expected 'Original plural' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
tr = po.GetN("Original", "Original plural", 1)
|
||||||
|
if tr != "Original" {
|
||||||
|
t.Errorf("Expected 'Original' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test empty translation strings
|
||||||
|
tr = po.Get("Empty translation")
|
||||||
|
if tr != "Empty translation" {
|
||||||
|
t.Errorf("Expected 'Empty translation' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
tr = po.Get("Empty plural form singular")
|
||||||
|
if tr != "Singular translated" {
|
||||||
|
t.Errorf("Expected 'Singular translated' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
tr = po.GetN("Empty plural form singular", "Empty plural form", 1)
|
||||||
|
if tr != "Singular translated" {
|
||||||
|
t.Errorf("Expected 'Singular translated' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
tr = po.GetN("Empty plural form singular", "Empty plural form", 2)
|
||||||
|
if tr != "Empty plural form" {
|
||||||
|
t.Errorf("Expected 'Empty plural form' but got '%s'", tr)
|
||||||
|
}
|
||||||
|
|
||||||
// Test last translation
|
// Test last translation
|
||||||
tr = po.Get("More")
|
tr = po.Get("More")
|
||||||
if tr != "More translation" {
|
if tr != "More translation" {
|
||||||
t.Errorf("Expected 'More translation' but got '%s'", tr)
|
t.Errorf("Expected 'More translation' but got '%s'", tr)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPoHeaders(t *testing.T) {
|
func TestPoHeaders(t *testing.T) {
|
||||||
// Set PO content
|
// Set PO content
|
||||||
str := `
|
str := `
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
# Initial comment
|
# Initial comment
|
||||||
# Headers below
|
# Headers below
|
||||||
"Language: en\n"
|
"Language: en\n"
|
||||||
@@ -167,7 +227,7 @@ msgstr ""
|
|||||||
# Some comment
|
# Some comment
|
||||||
msgid "Example"
|
msgid "Example"
|
||||||
msgstr "Translated example"
|
msgstr "Translated example"
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create po object
|
// Create po object
|
||||||
po := new(Po)
|
po := new(Po)
|
||||||
@@ -198,7 +258,7 @@ msgstr[0] "Singular form"
|
|||||||
msgstr[1] "Plural form 1"
|
msgstr[1] "Plural form 1"
|
||||||
msgstr[2] "Plural form 2"
|
msgstr[2] "Plural form 2"
|
||||||
msgstr[3] "Plural form 3"
|
msgstr[3] "Plural form 3"
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create po object
|
// Create po object
|
||||||
po := new(Po)
|
po := new(Po)
|
||||||
@@ -241,7 +301,7 @@ msgstr[0] "Singular form"
|
|||||||
msgstr[1] "Plural form 1"
|
msgstr[1] "Plural form 1"
|
||||||
msgstr[2] "Plural form 2"
|
msgstr[2] "Plural form 2"
|
||||||
msgstr[3] "Plural form 3"
|
msgstr[3] "Plural form 3"
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create po object
|
// Create po object
|
||||||
po := new(Po)
|
po := new(Po)
|
||||||
@@ -280,7 +340,7 @@ msgstr[0] "Singular form"
|
|||||||
msgstr[1] "Plural form 1"
|
msgstr[1] "Plural form 1"
|
||||||
msgstr[2] "Plural form 2"
|
msgstr[2] "Plural form 2"
|
||||||
msgstr[3] "Plural form 3"
|
msgstr[3] "Plural form 3"
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create po object
|
// Create po object
|
||||||
po := new(Po)
|
po := new(Po)
|
||||||
@@ -328,7 +388,7 @@ msgstr[0] "Singular form"
|
|||||||
msgstr[1] "Plural form 1"
|
msgstr[1] "Plural form 1"
|
||||||
msgstr[2] "Plural form 2"
|
msgstr[2] "Plural form 2"
|
||||||
msgstr[3] "Plural form 3"
|
msgstr[3] "Plural form 3"
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create po object
|
// Create po object
|
||||||
po := new(Po)
|
po := new(Po)
|
||||||
@@ -394,7 +454,7 @@ msgstr[0] "This one is the singular: %s"
|
|||||||
msgstr[1] "This one is the plural: %s"
|
msgstr[1] "This one is the plural: %s"
|
||||||
msgstr[2] "And this is the second plural form: %s"
|
msgstr[2] "And this is the second plural form: %s"
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
// Create Po object
|
// Create Po object
|
||||||
po := new(Po)
|
po := new(Po)
|
||||||
|
|||||||
2
vendor/github.com/mattn/anko/ast/doc.go
generated
vendored
2
vendor/github.com/mattn/anko/ast/doc.go
generated
vendored
@@ -1,2 +0,0 @@
|
|||||||
// Package ast implements abstruct-syntax-tree for anko.
|
|
||||||
package ast
|
|
||||||
201
vendor/github.com/mattn/anko/ast/expr.go
generated
vendored
201
vendor/github.com/mattn/anko/ast/expr.go
generated
vendored
@@ -1,201 +0,0 @@
|
|||||||
package ast
|
|
||||||
|
|
||||||
// Expr provides all of interfaces for expression.
|
|
||||||
type Expr interface {
|
|
||||||
Pos
|
|
||||||
expr()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExprImpl provide commonly implementations for Expr.
|
|
||||||
type ExprImpl struct {
|
|
||||||
PosImpl // ExprImpl provide Pos() function.
|
|
||||||
}
|
|
||||||
|
|
||||||
// expr provide restraint interface.
|
|
||||||
func (x *ExprImpl) expr() {}
|
|
||||||
|
|
||||||
// NumberExpr provide Number expression.
|
|
||||||
type NumberExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Lit string
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringExpr provide String expression.
|
|
||||||
type StringExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Lit string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArrayExpr provide Array expression.
|
|
||||||
type ArrayExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Exprs []Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// PairExpr provide one of Map key/value pair.
|
|
||||||
type PairExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Key string
|
|
||||||
Value Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapExpr provide Map expression.
|
|
||||||
type MapExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
MapExpr map[string]Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// IdentExpr provide identity expression.
|
|
||||||
type IdentExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Lit string
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnaryExpr provide unary minus expression. ex: -1, ^1, ~1.
|
|
||||||
type UnaryExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Operator string
|
|
||||||
Expr Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddrExpr provide referencing address expression.
|
|
||||||
type AddrExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Expr Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// DerefExpr provide dereferencing address expression.
|
|
||||||
type DerefExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Expr Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParenExpr provide parent block expression.
|
|
||||||
type ParenExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
SubExpr Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// BinOpExpr provide binary operator expression.
|
|
||||||
type BinOpExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Lhs Expr
|
|
||||||
Operator string
|
|
||||||
Rhs Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
type TernaryOpExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Expr Expr
|
|
||||||
Lhs Expr
|
|
||||||
Rhs Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallExpr provide calling expression.
|
|
||||||
type CallExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Func interface{}
|
|
||||||
Name string
|
|
||||||
SubExprs []Expr
|
|
||||||
VarArg bool
|
|
||||||
Go bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnonCallExpr provide anonymous calling expression. ex: func(){}().
|
|
||||||
type AnonCallExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Expr Expr
|
|
||||||
SubExprs []Expr
|
|
||||||
VarArg bool
|
|
||||||
Go bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// MemberExpr provide expression to refer menber.
|
|
||||||
type MemberExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Expr Expr
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ItemExpr provide expression to refer Map/Array item.
|
|
||||||
type ItemExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Value Expr
|
|
||||||
Index Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// SliceExpr provide expression to refer slice of Array.
|
|
||||||
type SliceExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Value Expr
|
|
||||||
Begin Expr
|
|
||||||
End Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// FuncExpr provide function expression.
|
|
||||||
type FuncExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Name string
|
|
||||||
Stmts []Stmt
|
|
||||||
Args []string
|
|
||||||
VarArg bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// LetExpr provide expression to let variable.
|
|
||||||
type LetExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Lhs Expr
|
|
||||||
Rhs Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// LetsExpr provide multiple expression of let.
|
|
||||||
type LetsExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Lhss []Expr
|
|
||||||
Operator string
|
|
||||||
Rhss []Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// AssocExpr provide expression to assoc operation.
|
|
||||||
type AssocExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Lhs Expr
|
|
||||||
Operator string
|
|
||||||
Rhs Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewExpr provide expression to make new instance.
|
|
||||||
type NewExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Name string
|
|
||||||
SubExprs []Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConstExpr provide expression for constant variable.
|
|
||||||
type ConstExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChanExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Lhs Expr
|
|
||||||
Rhs Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
type Type struct {
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
type MakeChanExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Type string
|
|
||||||
SizeExpr Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
type MakeArrayExpr struct {
|
|
||||||
ExprImpl
|
|
||||||
Type string
|
|
||||||
LenExpr Expr
|
|
||||||
CapExpr Expr
|
|
||||||
}
|
|
||||||
28
vendor/github.com/mattn/anko/ast/pos.go
generated
vendored
28
vendor/github.com/mattn/anko/ast/pos.go
generated
vendored
@@ -1,28 +0,0 @@
|
|||||||
package ast
|
|
||||||
|
|
||||||
// Position provides interface to store code locations.
|
|
||||||
type Position struct {
|
|
||||||
Line int
|
|
||||||
Column int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pos interface provies two functions to get/set the position for expression or statement.
|
|
||||||
type Pos interface {
|
|
||||||
Position() Position
|
|
||||||
SetPosition(Position)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PosImpl provies commonly implementations for Pos.
|
|
||||||
type PosImpl struct {
|
|
||||||
pos Position
|
|
||||||
}
|
|
||||||
|
|
||||||
// Position return the position of the expression or statement.
|
|
||||||
func (x *PosImpl) Position() Position {
|
|
||||||
return x.pos
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPosition is a function to specify position of the expression or statement.
|
|
||||||
func (x *PosImpl) SetPosition(pos Position) {
|
|
||||||
x.pos = pos
|
|
||||||
}
|
|
||||||
127
vendor/github.com/mattn/anko/ast/stmt.go
generated
vendored
127
vendor/github.com/mattn/anko/ast/stmt.go
generated
vendored
@@ -1,127 +0,0 @@
|
|||||||
package ast
|
|
||||||
|
|
||||||
// Stmt provides all of interfaces for statement.
|
|
||||||
type Stmt interface {
|
|
||||||
Pos
|
|
||||||
stmt()
|
|
||||||
}
|
|
||||||
|
|
||||||
// StmtImpl provide commonly implementations for Stmt..
|
|
||||||
type StmtImpl struct {
|
|
||||||
PosImpl // StmtImpl provide Pos() function.
|
|
||||||
}
|
|
||||||
|
|
||||||
// stmt provide restraint interface.
|
|
||||||
func (x *StmtImpl) stmt() {}
|
|
||||||
|
|
||||||
// ExprStmt provide expression statement.
|
|
||||||
type ExprStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Expr Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// IfStmt provide "if/else" statement.
|
|
||||||
type IfStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
If Expr
|
|
||||||
Then []Stmt
|
|
||||||
ElseIf []Stmt // This is array of IfStmt
|
|
||||||
Else []Stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
// TryStmt provide "try/catch/finally" statement.
|
|
||||||
type TryStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Try []Stmt
|
|
||||||
Var string
|
|
||||||
Catch []Stmt
|
|
||||||
Finally []Stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
// ForStmt provide "for in" expression statement.
|
|
||||||
type ForStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Var string
|
|
||||||
Value Expr
|
|
||||||
Stmts []Stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
// CForStmt provide C-style "for (;;)" expression statement.
|
|
||||||
type CForStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Expr1 Expr
|
|
||||||
Expr2 Expr
|
|
||||||
Expr3 Expr
|
|
||||||
Stmts []Stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoopStmt provide "for expr" expression statement.
|
|
||||||
type LoopStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Expr Expr
|
|
||||||
Stmts []Stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
// BreakStmt provide "break" expression statement.
|
|
||||||
type BreakStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContinueStmt provide "continue" expression statement.
|
|
||||||
type ContinueStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
}
|
|
||||||
|
|
||||||
// ForStmt provide "return" expression statement.
|
|
||||||
type ReturnStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Exprs []Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// ThrowStmt provide "throw" expression statement.
|
|
||||||
type ThrowStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Expr Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModuleStmt provide "module" expression statement.
|
|
||||||
type ModuleStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Name string
|
|
||||||
Stmts []Stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
// VarStmt provide statement to let variables in current scope.
|
|
||||||
type VarStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Names []string
|
|
||||||
Exprs []Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// SwitchStmt provide switch statement.
|
|
||||||
type SwitchStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Expr Expr
|
|
||||||
Cases []Stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
// CaseStmt provide switch/case statement.
|
|
||||||
type CaseStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Expr Expr
|
|
||||||
Stmts []Stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultStmt provide switch/default statement.
|
|
||||||
type DefaultStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Stmts []Stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
// LetsStmt provide multiple statement of let.
|
|
||||||
type LetsStmt struct {
|
|
||||||
StmtImpl
|
|
||||||
Lhss []Expr
|
|
||||||
Operator string
|
|
||||||
Rhss []Expr
|
|
||||||
}
|
|
||||||
7
vendor/github.com/mattn/anko/ast/token.go
generated
vendored
7
vendor/github.com/mattn/anko/ast/token.go
generated
vendored
@@ -1,7 +0,0 @@
|
|||||||
package ast
|
|
||||||
|
|
||||||
type Token struct {
|
|
||||||
PosImpl // StmtImpl provide Pos() function.
|
|
||||||
Tok int
|
|
||||||
Lit string
|
|
||||||
}
|
|
||||||
1997
vendor/github.com/mattn/anko/parser/parser.go
generated
vendored
1997
vendor/github.com/mattn/anko/parser/parser.go
generated
vendored
File diff suppressed because it is too large
Load Diff
705
vendor/github.com/mattn/anko/parser/parser.go.y
generated
vendored
705
vendor/github.com/mattn/anko/parser/parser.go.y
generated
vendored
@@ -1,705 +0,0 @@
|
|||||||
%{
|
|
||||||
package parser
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/mattn/anko/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
%}
|
|
||||||
|
|
||||||
%type<compstmt> compstmt
|
|
||||||
%type<stmts> stmts
|
|
||||||
%type<stmt> stmt
|
|
||||||
%type<stmt_if> stmt_if
|
|
||||||
%type<stmt_default> stmt_default
|
|
||||||
%type<stmt_case> stmt_case
|
|
||||||
%type<stmt_cases> stmt_cases
|
|
||||||
%type<typ> typ
|
|
||||||
%type<expr> expr
|
|
||||||
%type<exprs> exprs
|
|
||||||
%type<expr_many> expr_many
|
|
||||||
%type<expr_lets> expr_lets
|
|
||||||
%type<expr_pair> expr_pair
|
|
||||||
%type<expr_pairs> expr_pairs
|
|
||||||
%type<expr_idents> expr_idents
|
|
||||||
|
|
||||||
%union{
|
|
||||||
compstmt []ast.Stmt
|
|
||||||
stmt_if ast.Stmt
|
|
||||||
stmt_default ast.Stmt
|
|
||||||
stmt_case ast.Stmt
|
|
||||||
stmt_cases []ast.Stmt
|
|
||||||
stmts []ast.Stmt
|
|
||||||
stmt ast.Stmt
|
|
||||||
typ ast.Type
|
|
||||||
expr ast.Expr
|
|
||||||
exprs []ast.Expr
|
|
||||||
expr_many []ast.Expr
|
|
||||||
expr_lets ast.Expr
|
|
||||||
expr_pair ast.Expr
|
|
||||||
expr_pairs []ast.Expr
|
|
||||||
expr_idents []string
|
|
||||||
tok ast.Token
|
|
||||||
term ast.Token
|
|
||||||
terms ast.Token
|
|
||||||
opt_terms ast.Token
|
|
||||||
}
|
|
||||||
|
|
||||||
%token<tok> IDENT NUMBER STRING ARRAY VARARG FUNC RETURN VAR THROW IF ELSE FOR IN EQEQ NEQ GE LE OROR ANDAND NEW TRUE FALSE NIL MODULE TRY CATCH FINALLY PLUSEQ MINUSEQ MULEQ DIVEQ ANDEQ OREQ BREAK CONTINUE PLUSPLUS MINUSMINUS POW SHIFTLEFT SHIFTRIGHT SWITCH CASE DEFAULT GO CHAN MAKE OPCHAN ARRAYLIT
|
|
||||||
|
|
||||||
%right '='
|
|
||||||
%right '?' ':'
|
|
||||||
%left OROR
|
|
||||||
%left ANDAND
|
|
||||||
%left IDENT
|
|
||||||
%nonassoc EQEQ NEQ ','
|
|
||||||
%left '>' GE '<' LE SHIFTLEFT SHIFTRIGHT
|
|
||||||
|
|
||||||
%left '+' '-' PLUSPLUS MINUSMINUS
|
|
||||||
%left '*' '/' '%'
|
|
||||||
%right UNARY
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
compstmt : opt_terms
|
|
||||||
{
|
|
||||||
$$ = nil
|
|
||||||
}
|
|
||||||
| stmts opt_terms
|
|
||||||
{
|
|
||||||
$$ = $1
|
|
||||||
}
|
|
||||||
|
|
||||||
stmts :
|
|
||||||
{
|
|
||||||
$$ = nil
|
|
||||||
if l, ok := yylex.(*Lexer); ok {
|
|
||||||
l.stmts = $$
|
|
||||||
}
|
|
||||||
}
|
|
||||||
| opt_terms stmt
|
|
||||||
{
|
|
||||||
$$ = []ast.Stmt{$2}
|
|
||||||
if l, ok := yylex.(*Lexer); ok {
|
|
||||||
l.stmts = $$
|
|
||||||
}
|
|
||||||
}
|
|
||||||
| stmts terms stmt
|
|
||||||
{
|
|
||||||
if $3 != nil {
|
|
||||||
$$ = append($1, $3)
|
|
||||||
if l, ok := yylex.(*Lexer); ok {
|
|
||||||
l.stmts = $$
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stmt :
|
|
||||||
VAR expr_idents '=' expr_many
|
|
||||||
{
|
|
||||||
$$ = &ast.VarStmt{Names: $2, Exprs: $4}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '=' expr
|
|
||||||
{
|
|
||||||
$$ = &ast.LetsStmt{Lhss: []ast.Expr{$1}, Operator: "=", Rhss: []ast.Expr{$3}}
|
|
||||||
}
|
|
||||||
| expr_many '=' expr_many
|
|
||||||
{
|
|
||||||
$$ = &ast.LetsStmt{Lhss: $1, Operator: "=", Rhss: $3}
|
|
||||||
}
|
|
||||||
| BREAK
|
|
||||||
{
|
|
||||||
$$ = &ast.BreakStmt{}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| CONTINUE
|
|
||||||
{
|
|
||||||
$$ = &ast.ContinueStmt{}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| RETURN exprs
|
|
||||||
{
|
|
||||||
$$ = &ast.ReturnStmt{Exprs: $2}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| THROW expr
|
|
||||||
{
|
|
||||||
$$ = &ast.ThrowStmt{Expr: $2}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| MODULE IDENT '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.ModuleStmt{Name: $2.Lit, Stmts: $4}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| stmt_if
|
|
||||||
{
|
|
||||||
$$ = $1
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| FOR '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.LoopStmt{Stmts: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| FOR IDENT IN expr '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.ForStmt{Var: $2.Lit, Value: $4, Stmts: $6}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| FOR expr_lets ';' expr ';' expr '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.CForStmt{Expr1: $2, Expr2: $4, Expr3: $6, Stmts: $8}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| FOR expr '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.LoopStmt{Expr: $2, Stmts: $4}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| TRY '{' compstmt '}' CATCH IDENT '{' compstmt '}' FINALLY '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.TryStmt{Try: $3, Var: $6.Lit, Catch: $8, Finally: $12}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| TRY '{' compstmt '}' CATCH '{' compstmt '}' FINALLY '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.TryStmt{Try: $3, Catch: $7, Finally: $11}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| TRY '{' compstmt '}' CATCH IDENT '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.TryStmt{Try: $3, Var: $6.Lit, Catch: $8}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| TRY '{' compstmt '}' CATCH '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.TryStmt{Try: $3, Catch: $7}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| SWITCH expr '{' stmt_cases '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.SwitchStmt{Expr: $2, Cases: $4}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr
|
|
||||||
{
|
|
||||||
$$ = &ast.ExprStmt{Expr: $1}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
stmt_if :
|
|
||||||
stmt_if ELSE IF expr '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$1.(*ast.IfStmt).ElseIf = append($1.(*ast.IfStmt).ElseIf, &ast.IfStmt{If: $4, Then: $6})
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| stmt_if ELSE '{' compstmt '}'
|
|
||||||
{
|
|
||||||
if $$.(*ast.IfStmt).Else != nil {
|
|
||||||
yylex.Error("multiple else statement")
|
|
||||||
} else {
|
|
||||||
$$.(*ast.IfStmt).Else = append($$.(*ast.IfStmt).Else, $4...)
|
|
||||||
}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| IF expr '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.IfStmt{If: $2, Then: $4, Else: nil}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
|
|
||||||
stmt_cases :
|
|
||||||
{
|
|
||||||
$$ = []ast.Stmt{}
|
|
||||||
}
|
|
||||||
| opt_terms stmt_case
|
|
||||||
{
|
|
||||||
$$ = []ast.Stmt{$2}
|
|
||||||
}
|
|
||||||
| opt_terms stmt_default
|
|
||||||
{
|
|
||||||
$$ = []ast.Stmt{$2}
|
|
||||||
}
|
|
||||||
| stmt_cases stmt_case
|
|
||||||
{
|
|
||||||
$$ = append($1, $2)
|
|
||||||
}
|
|
||||||
| stmt_cases stmt_default
|
|
||||||
{
|
|
||||||
for _, stmt := range $1 {
|
|
||||||
if _, ok := stmt.(*ast.DefaultStmt); ok {
|
|
||||||
yylex.Error("multiple default statement")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$$ = append($1, $2)
|
|
||||||
}
|
|
||||||
|
|
||||||
stmt_case :
|
|
||||||
CASE expr ':' opt_terms compstmt
|
|
||||||
{
|
|
||||||
$$ = &ast.CaseStmt{Expr: $2, Stmts: $5}
|
|
||||||
}
|
|
||||||
|
|
||||||
stmt_default :
|
|
||||||
DEFAULT ':' opt_terms compstmt
|
|
||||||
{
|
|
||||||
$$ = &ast.DefaultStmt{Stmts: $4}
|
|
||||||
}
|
|
||||||
|
|
||||||
expr_pair :
|
|
||||||
STRING ':' expr
|
|
||||||
{
|
|
||||||
$$ = &ast.PairExpr{Key: $1.Lit, Value: $3}
|
|
||||||
}
|
|
||||||
|
|
||||||
expr_pairs :
|
|
||||||
{
|
|
||||||
$$ = []ast.Expr{}
|
|
||||||
}
|
|
||||||
| expr_pair
|
|
||||||
{
|
|
||||||
$$ = []ast.Expr{$1}
|
|
||||||
}
|
|
||||||
| expr_pairs ',' opt_terms expr_pair
|
|
||||||
{
|
|
||||||
$$ = append($1, $4)
|
|
||||||
}
|
|
||||||
|
|
||||||
expr_idents :
|
|
||||||
{
|
|
||||||
$$ = []string{}
|
|
||||||
}
|
|
||||||
| IDENT
|
|
||||||
{
|
|
||||||
$$ = []string{$1.Lit}
|
|
||||||
}
|
|
||||||
| expr_idents ',' opt_terms IDENT
|
|
||||||
{
|
|
||||||
$$ = append($1, $4.Lit)
|
|
||||||
}
|
|
||||||
|
|
||||||
expr_lets : expr_many '=' expr_many
|
|
||||||
{
|
|
||||||
$$ = &ast.LetsExpr{Lhss: $1, Operator: "=", Rhss: $3}
|
|
||||||
}
|
|
||||||
|
|
||||||
expr_many :
|
|
||||||
expr
|
|
||||||
{
|
|
||||||
$$ = []ast.Expr{$1}
|
|
||||||
}
|
|
||||||
| exprs ',' opt_terms expr
|
|
||||||
{
|
|
||||||
$$ = append($1, $4)
|
|
||||||
}
|
|
||||||
| exprs ',' opt_terms IDENT
|
|
||||||
{
|
|
||||||
$$ = append($1, &ast.IdentExpr{Lit: $4.Lit})
|
|
||||||
}
|
|
||||||
|
|
||||||
typ : IDENT
|
|
||||||
{
|
|
||||||
$$ = ast.Type{Name: $1.Lit}
|
|
||||||
}
|
|
||||||
| typ '.' IDENT
|
|
||||||
{
|
|
||||||
$$ = ast.Type{Name: $1.Name + "." + $3.Lit}
|
|
||||||
}
|
|
||||||
|
|
||||||
exprs :
|
|
||||||
{
|
|
||||||
$$ = nil
|
|
||||||
}
|
|
||||||
| expr
|
|
||||||
{
|
|
||||||
$$ = []ast.Expr{$1}
|
|
||||||
}
|
|
||||||
| exprs ',' opt_terms expr
|
|
||||||
{
|
|
||||||
$$ = append($1, $4)
|
|
||||||
}
|
|
||||||
| exprs ',' opt_terms IDENT
|
|
||||||
{
|
|
||||||
$$ = append($1, &ast.IdentExpr{Lit: $4.Lit})
|
|
||||||
}
|
|
||||||
|
|
||||||
expr :
|
|
||||||
IDENT
|
|
||||||
{
|
|
||||||
$$ = &ast.IdentExpr{Lit: $1.Lit}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| NUMBER
|
|
||||||
{
|
|
||||||
$$ = &ast.NumberExpr{Lit: $1.Lit}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| '-' expr %prec UNARY
|
|
||||||
{
|
|
||||||
$$ = &ast.UnaryExpr{Operator: "-", Expr: $2}
|
|
||||||
$$.SetPosition($2.Position())
|
|
||||||
}
|
|
||||||
| '!' expr %prec UNARY
|
|
||||||
{
|
|
||||||
$$ = &ast.UnaryExpr{Operator: "!", Expr: $2}
|
|
||||||
$$.SetPosition($2.Position())
|
|
||||||
}
|
|
||||||
| '^' expr %prec UNARY
|
|
||||||
{
|
|
||||||
$$ = &ast.UnaryExpr{Operator: "^", Expr: $2}
|
|
||||||
$$.SetPosition($2.Position())
|
|
||||||
}
|
|
||||||
| '&' IDENT %prec UNARY
|
|
||||||
{
|
|
||||||
$$ = &ast.AddrExpr{Expr: &ast.IdentExpr{Lit: $2.Lit}}
|
|
||||||
$$.SetPosition($2.Position())
|
|
||||||
}
|
|
||||||
| '&' expr '.' IDENT %prec UNARY
|
|
||||||
{
|
|
||||||
$$ = &ast.AddrExpr{Expr: &ast.MemberExpr{Expr: $2, Name: $4.Lit}}
|
|
||||||
$$.SetPosition($2.Position())
|
|
||||||
}
|
|
||||||
| '*' IDENT %prec UNARY
|
|
||||||
{
|
|
||||||
$$ = &ast.DerefExpr{Expr: &ast.IdentExpr{Lit: $2.Lit}}
|
|
||||||
$$.SetPosition($2.Position())
|
|
||||||
}
|
|
||||||
| '*' expr '.' IDENT %prec UNARY
|
|
||||||
{
|
|
||||||
$$ = &ast.DerefExpr{Expr: &ast.MemberExpr{Expr: $2, Name: $4.Lit}}
|
|
||||||
$$.SetPosition($2.Position())
|
|
||||||
}
|
|
||||||
| STRING
|
|
||||||
{
|
|
||||||
$$ = &ast.StringExpr{Lit: $1.Lit}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| TRUE
|
|
||||||
{
|
|
||||||
$$ = &ast.ConstExpr{Value: $1.Lit}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| FALSE
|
|
||||||
{
|
|
||||||
$$ = &ast.ConstExpr{Value: $1.Lit}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| NIL
|
|
||||||
{
|
|
||||||
$$ = &ast.ConstExpr{Value: $1.Lit}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '?' expr ':' expr
|
|
||||||
{
|
|
||||||
$$ = &ast.TernaryOpExpr{Expr: $1, Lhs: $3, Rhs: $5}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '.' IDENT
|
|
||||||
{
|
|
||||||
$$ = &ast.MemberExpr{Expr: $1, Name: $3.Lit}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| FUNC '(' expr_idents ')' '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.FuncExpr{Args: $3, Stmts: $6}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| FUNC '(' IDENT VARARG ')' '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.FuncExpr{Args: []string{$3.Lit}, Stmts: $7, VarArg: true}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| FUNC IDENT '(' expr_idents ')' '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.FuncExpr{Name: $2.Lit, Args: $4, Stmts: $7}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| FUNC IDENT '(' IDENT VARARG ')' '{' compstmt '}'
|
|
||||||
{
|
|
||||||
$$ = &ast.FuncExpr{Name: $2.Lit, Args: []string{$4.Lit}, Stmts: $8, VarArg: true}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| '[' opt_terms exprs opt_terms ']'
|
|
||||||
{
|
|
||||||
$$ = &ast.ArrayExpr{Exprs: $3}
|
|
||||||
if l, ok := yylex.(*Lexer); ok { $$.SetPosition(l.pos) }
|
|
||||||
}
|
|
||||||
| '[' opt_terms exprs ',' opt_terms ']'
|
|
||||||
{
|
|
||||||
$$ = &ast.ArrayExpr{Exprs: $3}
|
|
||||||
if l, ok := yylex.(*Lexer); ok { $$.SetPosition(l.pos) }
|
|
||||||
}
|
|
||||||
| '{' opt_terms expr_pairs opt_terms '}'
|
|
||||||
{
|
|
||||||
mapExpr := make(map[string]ast.Expr)
|
|
||||||
for _, v := range $3 {
|
|
||||||
mapExpr[v.(*ast.PairExpr).Key] = v.(*ast.PairExpr).Value
|
|
||||||
}
|
|
||||||
$$ = &ast.MapExpr{MapExpr: mapExpr}
|
|
||||||
if l, ok := yylex.(*Lexer); ok { $$.SetPosition(l.pos) }
|
|
||||||
}
|
|
||||||
| '{' opt_terms expr_pairs ',' opt_terms '}'
|
|
||||||
{
|
|
||||||
mapExpr := make(map[string]ast.Expr)
|
|
||||||
for _, v := range $3 {
|
|
||||||
mapExpr[v.(*ast.PairExpr).Key] = v.(*ast.PairExpr).Value
|
|
||||||
}
|
|
||||||
$$ = &ast.MapExpr{MapExpr: mapExpr}
|
|
||||||
if l, ok := yylex.(*Lexer); ok { $$.SetPosition(l.pos) }
|
|
||||||
}
|
|
||||||
| '(' expr ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.ParenExpr{SubExpr: $2}
|
|
||||||
if l, ok := yylex.(*Lexer); ok { $$.SetPosition(l.pos) }
|
|
||||||
}
|
|
||||||
| NEW IDENT '(' exprs ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.NewExpr{Name: $2.Lit, SubExprs: $4}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '+' expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "+", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '-' expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "-", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '*' expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "*", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '/' expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "/", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '%' expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "%", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr POW expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "**", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr SHIFTLEFT expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "<<", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr SHIFTRIGHT expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: ">>", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr EQEQ expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "==", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr NEQ expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "!=", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '>' expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: ">", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr GE expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: ">=", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '<' expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "<", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr LE expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "<=", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr PLUSEQ expr
|
|
||||||
{
|
|
||||||
$$ = &ast.AssocExpr{Lhs: $1, Operator: "+=", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr MINUSEQ expr
|
|
||||||
{
|
|
||||||
$$ = &ast.AssocExpr{Lhs: $1, Operator: "-=", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr MULEQ expr
|
|
||||||
{
|
|
||||||
$$ = &ast.AssocExpr{Lhs: $1, Operator: "*=", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr DIVEQ expr
|
|
||||||
{
|
|
||||||
$$ = &ast.AssocExpr{Lhs: $1, Operator: "/=", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr ANDEQ expr
|
|
||||||
{
|
|
||||||
$$ = &ast.AssocExpr{Lhs: $1, Operator: "&=", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr OREQ expr
|
|
||||||
{
|
|
||||||
$$ = &ast.AssocExpr{Lhs: $1, Operator: "|=", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr PLUSPLUS
|
|
||||||
{
|
|
||||||
$$ = &ast.AssocExpr{Lhs: $1, Operator: "++"}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr MINUSMINUS
|
|
||||||
{
|
|
||||||
$$ = &ast.AssocExpr{Lhs: $1, Operator: "--"}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '|' expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "|", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr OROR expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "||", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '&' expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "&", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr ANDAND expr
|
|
||||||
{
|
|
||||||
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "&&", Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| IDENT '(' exprs VARARG ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.CallExpr{Name: $1.Lit, SubExprs: $3, VarArg: true}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| IDENT '(' exprs ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.CallExpr{Name: $1.Lit, SubExprs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| GO IDENT '(' exprs VARARG ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.CallExpr{Name: $2.Lit, SubExprs: $4, VarArg: true, Go: true}
|
|
||||||
$$.SetPosition($2.Position())
|
|
||||||
}
|
|
||||||
| GO IDENT '(' exprs ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.CallExpr{Name: $2.Lit, SubExprs: $4, Go: true}
|
|
||||||
$$.SetPosition($2.Position())
|
|
||||||
}
|
|
||||||
| expr '(' exprs VARARG ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.AnonCallExpr{Expr: $1, SubExprs: $3, VarArg: true}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '(' exprs ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.AnonCallExpr{Expr: $1, SubExprs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| GO expr '(' exprs VARARG ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.AnonCallExpr{Expr: $2, SubExprs: $4, VarArg: true, Go: true}
|
|
||||||
$$.SetPosition($2.Position())
|
|
||||||
}
|
|
||||||
| GO expr '(' exprs ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.AnonCallExpr{Expr: $2, SubExprs: $4, Go: true}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| IDENT '[' expr ']'
|
|
||||||
{
|
|
||||||
$$ = &ast.ItemExpr{Value: &ast.IdentExpr{Lit: $1.Lit}, Index: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '[' expr ']'
|
|
||||||
{
|
|
||||||
$$ = &ast.ItemExpr{Value: $1, Index: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| IDENT '[' expr ':' expr ']'
|
|
||||||
{
|
|
||||||
$$ = &ast.SliceExpr{Value: &ast.IdentExpr{Lit: $1.Lit}, Begin: $3, End: $5}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr '[' expr ':' expr ']'
|
|
||||||
{
|
|
||||||
$$ = &ast.SliceExpr{Value: $1, Begin: $3, End: $5}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| MAKE '(' CHAN typ ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.MakeChanExpr{Type: $4.Name, SizeExpr: nil}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| MAKE '(' CHAN typ ',' expr ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.MakeChanExpr{Type: $4.Name, SizeExpr: $6}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| MAKE '(' ARRAYLIT typ ',' expr ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.MakeArrayExpr{Type: $4.Name, LenExpr: $6}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| MAKE '(' ARRAYLIT typ ',' expr ',' expr ')'
|
|
||||||
{
|
|
||||||
$$ = &ast.MakeArrayExpr{Type: $4.Name, LenExpr: $6, CapExpr: $8}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| expr OPCHAN expr
|
|
||||||
{
|
|
||||||
$$ = &ast.ChanExpr{Lhs: $1, Rhs: $3}
|
|
||||||
$$.SetPosition($1.Position())
|
|
||||||
}
|
|
||||||
| OPCHAN expr
|
|
||||||
{
|
|
||||||
$$ = &ast.ChanExpr{Rhs: $2}
|
|
||||||
$$.SetPosition($2.Position())
|
|
||||||
}
|
|
||||||
|
|
||||||
opt_terms : /* none */
|
|
||||||
| terms
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
terms : term
|
|
||||||
{
|
|
||||||
}
|
|
||||||
| terms term
|
|
||||||
{
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
term : ';'
|
|
||||||
{
|
|
||||||
}
|
|
||||||
| '\n'
|
|
||||||
{
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
%%
|
|
||||||
2
vendor/github.com/mattn/anko/vm/doc.go
generated
vendored
2
vendor/github.com/mattn/anko/vm/doc.go
generated
vendored
@@ -1,2 +0,0 @@
|
|||||||
// Package vm implements virtual-machine for anko.
|
|
||||||
package vm
|
|
||||||
1504
vendor/github.com/mattn/anko/vm/vm.go
generated
vendored
1504
vendor/github.com/mattn/anko/vm/vm.go
generated
vendored
File diff suppressed because it is too large
Load Diff
104
vendor/github.com/mattn/kinako/ast/expr.go
generated
vendored
Normal file
104
vendor/github.com/mattn/kinako/ast/expr.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
type Token struct {
|
||||||
|
Tok int
|
||||||
|
Lit string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position provides interface to store code locations.
|
||||||
|
type Position struct {
|
||||||
|
Line int
|
||||||
|
Column int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expr provides all of interfaces for expression.
|
||||||
|
type Expr interface {
|
||||||
|
expr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExprImpl provide commonly implementations for Expr.
|
||||||
|
type ExprImpl struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// expr provide restraint interface.
|
||||||
|
func (x *ExprImpl) expr() {}
|
||||||
|
|
||||||
|
// NumberExpr provide Number expression.
|
||||||
|
type NumberExpr struct {
|
||||||
|
ExprImpl
|
||||||
|
Lit string
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnaryExpr provide unary minus expression. ex: -1, ^1, ~1.
|
||||||
|
type UnaryExpr struct {
|
||||||
|
ExprImpl
|
||||||
|
Operator string
|
||||||
|
Expr Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
// IdentExpr provide identity expression.
|
||||||
|
type IdentExpr struct {
|
||||||
|
ExprImpl
|
||||||
|
Lit string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stmt provides all of interfaces for statement.
|
||||||
|
type Stmt interface {
|
||||||
|
stmt()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StmtImpl provide commonly implementations for Stmt..
|
||||||
|
type StmtImpl struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// stmt provide restraint interface.
|
||||||
|
func (x *StmtImpl) stmt() {}
|
||||||
|
|
||||||
|
// LetsStmt provide multiple statement of let.
|
||||||
|
type LetsStmt struct {
|
||||||
|
StmtImpl
|
||||||
|
Lhss []Expr
|
||||||
|
Operator string
|
||||||
|
Rhss []Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringExpr provide String expression.
|
||||||
|
type StringExpr struct {
|
||||||
|
ExprImpl
|
||||||
|
Lit string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TernaryOpExpr struct {
|
||||||
|
ExprImpl
|
||||||
|
Expr Expr
|
||||||
|
Lhs Expr
|
||||||
|
Rhs Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParenExpr provide parent block expression.
|
||||||
|
type ParenExpr struct {
|
||||||
|
ExprImpl
|
||||||
|
SubExpr Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
// BinOpExpr provide binary operator expression.
|
||||||
|
type BinOpExpr struct {
|
||||||
|
ExprImpl
|
||||||
|
Lhs Expr
|
||||||
|
Operator string
|
||||||
|
Rhs Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExprStmt provide expression statement.
|
||||||
|
type ExprStmt struct {
|
||||||
|
StmtImpl
|
||||||
|
Expr Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetStmt provide statement of let.
|
||||||
|
type LetStmt struct {
|
||||||
|
StmtImpl
|
||||||
|
Lhs Expr
|
||||||
|
Operator string
|
||||||
|
Rhs Expr
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
all : parser.go
|
all : parser.go
|
||||||
|
|
||||||
parser.go : parser.go.y
|
parser.go : parser.go.y
|
||||||
go tool yacc -o $@ parser.go.y
|
goyacc -o $@ parser.go.y
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
// Package parser implements parser for anko.
|
|
||||||
package parser
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
"github.com/mattn/anko/ast"
|
"github.com/mattn/kinako/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -17,7 +17,6 @@ const (
|
|||||||
// It can be Error inteface with type cast which can call Pos().
|
// It can be Error inteface with type cast which can call Pos().
|
||||||
type Error struct {
|
type Error struct {
|
||||||
Message string
|
Message string
|
||||||
Pos ast.Position
|
|
||||||
Filename string
|
Filename string
|
||||||
Fatal bool
|
Fatal bool
|
||||||
}
|
}
|
||||||
@@ -35,34 +34,6 @@ type Scanner struct {
|
|||||||
line int
|
line int
|
||||||
}
|
}
|
||||||
|
|
||||||
// opName is correction of operation names.
|
|
||||||
var opName = map[string]int{
|
|
||||||
"func": FUNC,
|
|
||||||
"return": RETURN,
|
|
||||||
"var": VAR,
|
|
||||||
"throw": THROW,
|
|
||||||
"if": IF,
|
|
||||||
"for": FOR,
|
|
||||||
"break": BREAK,
|
|
||||||
"continue": CONTINUE,
|
|
||||||
"in": IN,
|
|
||||||
"else": ELSE,
|
|
||||||
"new": NEW,
|
|
||||||
"true": TRUE,
|
|
||||||
"false": FALSE,
|
|
||||||
"nil": NIL,
|
|
||||||
"module": MODULE,
|
|
||||||
"try": TRY,
|
|
||||||
"catch": CATCH,
|
|
||||||
"finally": FINALLY,
|
|
||||||
"switch": SWITCH,
|
|
||||||
"case": CASE,
|
|
||||||
"default": DEFAULT,
|
|
||||||
"go": GO,
|
|
||||||
"chan": CHAN,
|
|
||||||
"make": MAKE,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init resets code to scan.
|
// Init resets code to scan.
|
||||||
func (s *Scanner) Init(src string) {
|
func (s *Scanner) Init(src string) {
|
||||||
s.src = []rune(src)
|
s.src = []rune(src)
|
||||||
@@ -75,15 +46,11 @@ retry:
|
|||||||
pos = s.pos()
|
pos = s.pos()
|
||||||
switch ch := s.peek(); {
|
switch ch := s.peek(); {
|
||||||
case isLetter(ch):
|
case isLetter(ch):
|
||||||
|
tok = IDENT
|
||||||
lit, err = s.scanIdentifier()
|
lit, err = s.scanIdentifier()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if name, ok := opName[lit]; ok {
|
|
||||||
tok = name
|
|
||||||
} else {
|
|
||||||
tok = IDENT
|
|
||||||
}
|
|
||||||
case isDigit(ch):
|
case isDigit(ch):
|
||||||
tok = NUMBER
|
tok = NUMBER
|
||||||
lit, err = s.scanNumber()
|
lit, err = s.scanNumber()
|
||||||
@@ -140,58 +107,17 @@ retry:
|
|||||||
lit = string(ch)
|
lit = string(ch)
|
||||||
}
|
}
|
||||||
case '+':
|
case '+':
|
||||||
s.next()
|
tok = int(ch)
|
||||||
switch s.peek() {
|
lit = string(ch)
|
||||||
case '+':
|
|
||||||
tok = PLUSPLUS
|
|
||||||
lit = "++"
|
|
||||||
case '=':
|
|
||||||
tok = PLUSEQ
|
|
||||||
lit = "+="
|
|
||||||
default:
|
|
||||||
s.back()
|
|
||||||
tok = int(ch)
|
|
||||||
lit = string(ch)
|
|
||||||
}
|
|
||||||
case '-':
|
case '-':
|
||||||
s.next()
|
tok = int(ch)
|
||||||
switch s.peek() {
|
lit = string(ch)
|
||||||
case '-':
|
|
||||||
tok = MINUSMINUS
|
|
||||||
lit = "--"
|
|
||||||
case '=':
|
|
||||||
tok = MINUSEQ
|
|
||||||
lit = "-="
|
|
||||||
default:
|
|
||||||
s.back()
|
|
||||||
tok = int(ch)
|
|
||||||
lit = string(ch)
|
|
||||||
}
|
|
||||||
case '*':
|
case '*':
|
||||||
s.next()
|
tok = int(ch)
|
||||||
switch s.peek() {
|
lit = string(ch)
|
||||||
case '*':
|
|
||||||
tok = POW
|
|
||||||
lit = "**"
|
|
||||||
case '=':
|
|
||||||
tok = MULEQ
|
|
||||||
lit = "*="
|
|
||||||
default:
|
|
||||||
s.back()
|
|
||||||
tok = int(ch)
|
|
||||||
lit = string(ch)
|
|
||||||
}
|
|
||||||
case '/':
|
case '/':
|
||||||
s.next()
|
tok = int(ch)
|
||||||
switch s.peek() {
|
lit = string(ch)
|
||||||
case '=':
|
|
||||||
tok = DIVEQ
|
|
||||||
lit = "/="
|
|
||||||
default:
|
|
||||||
s.back()
|
|
||||||
tok = int(ch)
|
|
||||||
lit = string(ch)
|
|
||||||
}
|
|
||||||
case '>':
|
case '>':
|
||||||
s.next()
|
s.next()
|
||||||
switch s.peek() {
|
switch s.peek() {
|
||||||
@@ -209,9 +135,6 @@ retry:
|
|||||||
case '<':
|
case '<':
|
||||||
s.next()
|
s.next()
|
||||||
switch s.peek() {
|
switch s.peek() {
|
||||||
case '-':
|
|
||||||
tok = OPCHAN
|
|
||||||
lit = "<-"
|
|
||||||
case '=':
|
case '=':
|
||||||
tok = LE
|
tok = LE
|
||||||
lit = "<="
|
lit = "<="
|
||||||
@@ -229,9 +152,6 @@ retry:
|
|||||||
case '|':
|
case '|':
|
||||||
tok = OROR
|
tok = OROR
|
||||||
lit = "||"
|
lit = "||"
|
||||||
case '=':
|
|
||||||
tok = OREQ
|
|
||||||
lit = "|="
|
|
||||||
default:
|
default:
|
||||||
s.back()
|
s.back()
|
||||||
tok = int(ch)
|
tok = int(ch)
|
||||||
@@ -243,50 +163,24 @@ retry:
|
|||||||
case '&':
|
case '&':
|
||||||
tok = ANDAND
|
tok = ANDAND
|
||||||
lit = "&&"
|
lit = "&&"
|
||||||
case '=':
|
|
||||||
tok = ANDEQ
|
|
||||||
lit = "&="
|
|
||||||
default:
|
default:
|
||||||
s.back()
|
s.back()
|
||||||
tok = int(ch)
|
tok = int(ch)
|
||||||
lit = string(ch)
|
lit = string(ch)
|
||||||
}
|
}
|
||||||
case '.':
|
case '.':
|
||||||
s.next()
|
tok = int(ch)
|
||||||
if s.peek() == '.' {
|
lit = string(ch)
|
||||||
s.next()
|
case '\n':
|
||||||
if s.peek() == '.' {
|
tok = int(ch)
|
||||||
tok = VARARG
|
lit = string(ch)
|
||||||
} else {
|
case '(', ')', ':', ';', '%', '?', '{', '}', ',', '[', ']', '^':
|
||||||
err = fmt.Errorf(`syntax error "%s"`, "..")
|
tok = int(ch)
|
||||||
return
|
lit = string(ch)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s.back()
|
|
||||||
tok = int(ch)
|
|
||||||
lit = string(ch)
|
|
||||||
}
|
|
||||||
case '(', ')', ':', ';', '%', '?', '{', '}', ',', '[', ']', '^', '\n':
|
|
||||||
s.next()
|
|
||||||
if ch == '[' && s.peek() == ']' {
|
|
||||||
s.next()
|
|
||||||
if isLetter(s.peek()) {
|
|
||||||
s.back()
|
|
||||||
tok = ARRAYLIT
|
|
||||||
lit = "[]"
|
|
||||||
} else {
|
|
||||||
s.back()
|
|
||||||
s.back()
|
|
||||||
tok = int(ch)
|
|
||||||
lit = string(ch)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s.back()
|
|
||||||
tok = int(ch)
|
|
||||||
lit = string(ch)
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf(`syntax error "%s"`, string(ch))
|
err = fmt.Errorf(`syntax error "%s"`, string(ch))
|
||||||
|
tok = int(ch)
|
||||||
|
lit = string(ch)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.next()
|
s.next()
|
||||||
@@ -296,7 +190,7 @@ retry:
|
|||||||
|
|
||||||
// isLetter returns true if the rune is a letter for identity.
|
// isLetter returns true if the rune is a letter for identity.
|
||||||
func isLetter(ch rune) bool {
|
func isLetter(ch rune) bool {
|
||||||
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_'
|
return unicode.IsLetter(ch) || ch == '_'
|
||||||
}
|
}
|
||||||
|
|
||||||
// isDigit returns true if the rune is a number.
|
// isDigit returns true if the rune is a number.
|
||||||
@@ -498,10 +392,9 @@ type Lexer struct {
|
|||||||
func (l *Lexer) Lex(lval *yySymType) int {
|
func (l *Lexer) Lex(lval *yySymType) int {
|
||||||
tok, lit, pos, err := l.s.Scan()
|
tok, lit, pos, err := l.s.Scan()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.e = &Error{Message: fmt.Sprintf("%s", err.Error()), Pos: pos, Fatal: true}
|
l.e = &Error{Message: fmt.Sprintf("%s", err.Error()), Fatal: true}
|
||||||
}
|
}
|
||||||
lval.tok = ast.Token{Tok: tok, Lit: lit}
|
lval.tok = ast.Token{Tok: tok, Lit: lit}
|
||||||
lval.tok.SetPosition(pos)
|
|
||||||
l.lit = lit
|
l.lit = lit
|
||||||
l.pos = pos
|
l.pos = pos
|
||||||
return tok
|
return tok
|
||||||
@@ -509,7 +402,7 @@ func (l *Lexer) Lex(lval *yySymType) int {
|
|||||||
|
|
||||||
// Error sets parse error.
|
// Error sets parse error.
|
||||||
func (l *Lexer) Error(msg string) {
|
func (l *Lexer) Error(msg string) {
|
||||||
l.e = &Error{Message: msg, Pos: l.pos, Fatal: false}
|
l.e = &Error{Message: msg, Fatal: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parser provides way to parse the code using Scanner.
|
// Parser provides way to parse the code using Scanner.
|
||||||
@@ -521,6 +414,10 @@ func Parse(s *Scanner) ([]ast.Stmt, error) {
|
|||||||
return l.stmts, l.e
|
return l.stmts, l.e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EnableErrorVerbose() {
|
||||||
|
yyErrorVerbose = true
|
||||||
|
}
|
||||||
|
|
||||||
// ParserSrc provides way to parse the code from source.
|
// ParserSrc provides way to parse the code from source.
|
||||||
func ParseSrc(src string) ([]ast.Stmt, error) {
|
func ParseSrc(src string) ([]ast.Stmt, error) {
|
||||||
scanner := &Scanner{
|
scanner := &Scanner{
|
||||||
752
vendor/github.com/mattn/kinako/parser/parser.go
generated
vendored
Normal file
752
vendor/github.com/mattn/kinako/parser/parser.go
generated
vendored
Normal file
@@ -0,0 +1,752 @@
|
|||||||
|
//line parser.go.y:2
|
||||||
|
package parser
|
||||||
|
|
||||||
|
import __yyfmt__ "fmt"
|
||||||
|
|
||||||
|
//line parser.go.y:2
|
||||||
|
import (
|
||||||
|
"github.com/mattn/kinako/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
//line parser.go.y:15
|
||||||
|
type yySymType struct {
|
||||||
|
yys int
|
||||||
|
compstmt []ast.Stmt
|
||||||
|
stmts []ast.Stmt
|
||||||
|
stmt ast.Stmt
|
||||||
|
expr ast.Expr
|
||||||
|
tok ast.Token
|
||||||
|
term ast.Token
|
||||||
|
terms ast.Token
|
||||||
|
opt_terms ast.Token
|
||||||
|
}
|
||||||
|
|
||||||
|
const IDENT = 57346
|
||||||
|
const NUMBER = 57347
|
||||||
|
const STRING = 57348
|
||||||
|
const EQEQ = 57349
|
||||||
|
const NEQ = 57350
|
||||||
|
const GE = 57351
|
||||||
|
const LE = 57352
|
||||||
|
const OROR = 57353
|
||||||
|
const ANDAND = 57354
|
||||||
|
const POW = 57355
|
||||||
|
const SHIFTLEFT = 57356
|
||||||
|
const SHIFTRIGHT = 57357
|
||||||
|
const PLUSPLUS = 57358
|
||||||
|
const MINUSMINUS = 57359
|
||||||
|
const UNARY = 57360
|
||||||
|
|
||||||
|
var yyToknames = [...]string{
|
||||||
|
"$end",
|
||||||
|
"error",
|
||||||
|
"$unk",
|
||||||
|
"IDENT",
|
||||||
|
"NUMBER",
|
||||||
|
"STRING",
|
||||||
|
"EQEQ",
|
||||||
|
"NEQ",
|
||||||
|
"GE",
|
||||||
|
"LE",
|
||||||
|
"OROR",
|
||||||
|
"ANDAND",
|
||||||
|
"POW",
|
||||||
|
"'='",
|
||||||
|
"'?'",
|
||||||
|
"':'",
|
||||||
|
"','",
|
||||||
|
"'>'",
|
||||||
|
"'<'",
|
||||||
|
"SHIFTLEFT",
|
||||||
|
"SHIFTRIGHT",
|
||||||
|
"'+'",
|
||||||
|
"'-'",
|
||||||
|
"PLUSPLUS",
|
||||||
|
"MINUSMINUS",
|
||||||
|
"'*'",
|
||||||
|
"'/'",
|
||||||
|
"'%'",
|
||||||
|
"UNARY",
|
||||||
|
"'!'",
|
||||||
|
"'^'",
|
||||||
|
"'('",
|
||||||
|
"')'",
|
||||||
|
"'|'",
|
||||||
|
"'&'",
|
||||||
|
"';'",
|
||||||
|
"'\\n'",
|
||||||
|
}
|
||||||
|
var yyStatenames = [...]string{}
|
||||||
|
|
||||||
|
const yyEofCode = 1
|
||||||
|
const yyErrCode = 2
|
||||||
|
const yyInitialStackSize = 16
|
||||||
|
|
||||||
|
//line parser.go.y:194
|
||||||
|
|
||||||
|
//line yacctab:1
|
||||||
|
var yyExca = [...]int{
|
||||||
|
-1, 1,
|
||||||
|
1, -1,
|
||||||
|
-2, 0,
|
||||||
|
-1, 49,
|
||||||
|
7, 0,
|
||||||
|
8, 0,
|
||||||
|
-2, 20,
|
||||||
|
-1, 50,
|
||||||
|
7, 0,
|
||||||
|
8, 0,
|
||||||
|
-2, 21,
|
||||||
|
}
|
||||||
|
|
||||||
|
const yyNprod = 36
|
||||||
|
const yyPrivate = 57344
|
||||||
|
|
||||||
|
var yyTokenNames []string
|
||||||
|
var yyStates []string
|
||||||
|
|
||||||
|
const yyLast = 249
|
||||||
|
|
||||||
|
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,
|
||||||
|
31, 0, 0, 22, 23, 5, 0, 24, 25, 26,
|
||||||
|
19, 61, 0, 41, 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,
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
var yyPgo = [...]int{
|
||||||
|
|
||||||
|
0, 45, 8, 44, 0, 16, 5, 55,
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
var yyChk = [...]int{
|
||||||
|
|
||||||
|
-1000, -1, -5, -2, -6, -7, 36, 37, -3, -4,
|
||||||
|
4, 5, 23, 30, 31, 6, 32, -5, -6, -7,
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
var yyDef = [...]int{
|
||||||
|
|
||||||
|
30, -2, 1, 30, 31, 32, 34, 35, 3, 6,
|
||||||
|
7, 8, 0, 0, 0, 12, 0, 2, 31, 33,
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
var yyTok1 = [...]int{
|
||||||
|
|
||||||
|
1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
37, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 30, 3, 3, 3, 28, 35, 3,
|
||||||
|
32, 33, 26, 22, 17, 23, 3, 27, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 16, 36,
|
||||||
|
19, 14, 18, 15, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 31, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 34,
|
||||||
|
}
|
||||||
|
var yyTok2 = [...]int{
|
||||||
|
|
||||||
|
2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||||
|
12, 13, 20, 21, 24, 25, 29,
|
||||||
|
}
|
||||||
|
var yyTok3 = [...]int{
|
||||||
|
0,
|
||||||
|
}
|
||||||
|
|
||||||
|
var yyErrorMessages = [...]struct {
|
||||||
|
state int
|
||||||
|
token int
|
||||||
|
msg string
|
||||||
|
}{}
|
||||||
|
|
||||||
|
//line yaccpar:1
|
||||||
|
|
||||||
|
/* parser for yacc output */
|
||||||
|
|
||||||
|
var (
|
||||||
|
yyDebug = 0
|
||||||
|
yyErrorVerbose = false
|
||||||
|
)
|
||||||
|
|
||||||
|
type yyLexer interface {
|
||||||
|
Lex(lval *yySymType) int
|
||||||
|
Error(s string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type yyParser interface {
|
||||||
|
Parse(yyLexer) int
|
||||||
|
Lookahead() int
|
||||||
|
}
|
||||||
|
|
||||||
|
type yyParserImpl struct {
|
||||||
|
lval yySymType
|
||||||
|
stack [yyInitialStackSize]yySymType
|
||||||
|
char int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *yyParserImpl) Lookahead() int {
|
||||||
|
return p.char
|
||||||
|
}
|
||||||
|
|
||||||
|
func yyNewParser() yyParser {
|
||||||
|
return &yyParserImpl{}
|
||||||
|
}
|
||||||
|
|
||||||
|
const yyFlag = -1000
|
||||||
|
|
||||||
|
func yyTokname(c int) string {
|
||||||
|
if c >= 1 && c-1 < len(yyToknames) {
|
||||||
|
if yyToknames[c-1] != "" {
|
||||||
|
return yyToknames[c-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return __yyfmt__.Sprintf("tok-%v", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func yyStatname(s int) string {
|
||||||
|
if s >= 0 && s < len(yyStatenames) {
|
||||||
|
if yyStatenames[s] != "" {
|
||||||
|
return yyStatenames[s]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return __yyfmt__.Sprintf("state-%v", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func yyErrorMessage(state, lookAhead int) string {
|
||||||
|
const TOKSTART = 4
|
||||||
|
|
||||||
|
if !yyErrorVerbose {
|
||||||
|
return "syntax error"
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range yyErrorMessages {
|
||||||
|
if e.state == state && e.token == lookAhead {
|
||||||
|
return "syntax error: " + e.msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res := "syntax error: unexpected " + yyTokname(lookAhead)
|
||||||
|
|
||||||
|
// To match Bison, suggest at most four expected tokens.
|
||||||
|
expected := make([]int, 0, 4)
|
||||||
|
|
||||||
|
// Look for shiftable tokens.
|
||||||
|
base := yyPact[state]
|
||||||
|
for tok := TOKSTART; tok-1 < len(yyToknames); tok++ {
|
||||||
|
if n := base + tok; n >= 0 && n < yyLast && yyChk[yyAct[n]] == tok {
|
||||||
|
if len(expected) == cap(expected) {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
expected = append(expected, tok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if yyDef[state] == -2 {
|
||||||
|
i := 0
|
||||||
|
for yyExca[i] != -1 || yyExca[i+1] != state {
|
||||||
|
i += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for tokens that we accept or reduce.
|
||||||
|
for i += 2; yyExca[i] >= 0; i += 2 {
|
||||||
|
tok := yyExca[i]
|
||||||
|
if tok < TOKSTART || yyExca[i+1] == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(expected) == cap(expected) {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
expected = append(expected, tok)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the default action is to accept or reduce, give up.
|
||||||
|
if yyExca[i+1] != 0 {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tok := range expected {
|
||||||
|
if i == 0 {
|
||||||
|
res += ", expecting "
|
||||||
|
} else {
|
||||||
|
res += " or "
|
||||||
|
}
|
||||||
|
res += yyTokname(tok)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func yylex1(lex yyLexer, lval *yySymType) (char, token int) {
|
||||||
|
token = 0
|
||||||
|
char = lex.Lex(lval)
|
||||||
|
if char <= 0 {
|
||||||
|
token = yyTok1[0]
|
||||||
|
goto out
|
||||||
|
}
|
||||||
|
if char < len(yyTok1) {
|
||||||
|
token = yyTok1[char]
|
||||||
|
goto out
|
||||||
|
}
|
||||||
|
if char >= yyPrivate {
|
||||||
|
if char < yyPrivate+len(yyTok2) {
|
||||||
|
token = yyTok2[char-yyPrivate]
|
||||||
|
goto out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := 0; i < len(yyTok3); i += 2 {
|
||||||
|
token = yyTok3[i+0]
|
||||||
|
if token == char {
|
||||||
|
token = yyTok3[i+1]
|
||||||
|
goto out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if token == 0 {
|
||||||
|
token = yyTok2[1] /* unknown char */
|
||||||
|
}
|
||||||
|
if yyDebug >= 3 {
|
||||||
|
__yyfmt__.Printf("lex %s(%d)\n", yyTokname(token), uint(char))
|
||||||
|
}
|
||||||
|
return char, token
|
||||||
|
}
|
||||||
|
|
||||||
|
func yyParse(yylex yyLexer) int {
|
||||||
|
return yyNewParser().Parse(yylex)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int {
|
||||||
|
var yyn int
|
||||||
|
var yyVAL yySymType
|
||||||
|
var yyDollar []yySymType
|
||||||
|
_ = yyDollar // silence set and not used
|
||||||
|
yyS := yyrcvr.stack[:]
|
||||||
|
|
||||||
|
Nerrs := 0 /* number of errors */
|
||||||
|
Errflag := 0 /* error recovery flag */
|
||||||
|
yystate := 0
|
||||||
|
yyrcvr.char = -1
|
||||||
|
yytoken := -1 // yyrcvr.char translated into internal numbering
|
||||||
|
defer func() {
|
||||||
|
// Make sure we report no lookahead when not parsing.
|
||||||
|
yystate = -1
|
||||||
|
yyrcvr.char = -1
|
||||||
|
yytoken = -1
|
||||||
|
}()
|
||||||
|
yyp := -1
|
||||||
|
goto yystack
|
||||||
|
|
||||||
|
ret0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
ret1:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
yystack:
|
||||||
|
/* put a state and value onto the stack */
|
||||||
|
if yyDebug >= 4 {
|
||||||
|
__yyfmt__.Printf("char %v in %v\n", yyTokname(yytoken), yyStatname(yystate))
|
||||||
|
}
|
||||||
|
|
||||||
|
yyp++
|
||||||
|
if yyp >= len(yyS) {
|
||||||
|
nyys := make([]yySymType, len(yyS)*2)
|
||||||
|
copy(nyys, yyS)
|
||||||
|
yyS = nyys
|
||||||
|
}
|
||||||
|
yyS[yyp] = yyVAL
|
||||||
|
yyS[yyp].yys = yystate
|
||||||
|
|
||||||
|
yynewstate:
|
||||||
|
yyn = yyPact[yystate]
|
||||||
|
if yyn <= yyFlag {
|
||||||
|
goto yydefault /* simple state */
|
||||||
|
}
|
||||||
|
if yyrcvr.char < 0 {
|
||||||
|
yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval)
|
||||||
|
}
|
||||||
|
yyn += yytoken
|
||||||
|
if yyn < 0 || yyn >= yyLast {
|
||||||
|
goto yydefault
|
||||||
|
}
|
||||||
|
yyn = yyAct[yyn]
|
||||||
|
if yyChk[yyn] == yytoken { /* valid shift */
|
||||||
|
yyrcvr.char = -1
|
||||||
|
yytoken = -1
|
||||||
|
yyVAL = yyrcvr.lval
|
||||||
|
yystate = yyn
|
||||||
|
if Errflag > 0 {
|
||||||
|
Errflag--
|
||||||
|
}
|
||||||
|
goto yystack
|
||||||
|
}
|
||||||
|
|
||||||
|
yydefault:
|
||||||
|
/* default state action */
|
||||||
|
yyn = yyDef[yystate]
|
||||||
|
if yyn == -2 {
|
||||||
|
if yyrcvr.char < 0 {
|
||||||
|
yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look through exception table */
|
||||||
|
xi := 0
|
||||||
|
for {
|
||||||
|
if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
xi += 2
|
||||||
|
}
|
||||||
|
for xi += 2; ; xi += 2 {
|
||||||
|
yyn = yyExca[xi+0]
|
||||||
|
if yyn < 0 || yyn == yytoken {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yyn = yyExca[xi+1]
|
||||||
|
if yyn < 0 {
|
||||||
|
goto ret0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if yyn == 0 {
|
||||||
|
/* error ... attempt to resume parsing */
|
||||||
|
switch Errflag {
|
||||||
|
case 0: /* brand new error */
|
||||||
|
yylex.Error(yyErrorMessage(yystate, yytoken))
|
||||||
|
Nerrs++
|
||||||
|
if yyDebug >= 1 {
|
||||||
|
__yyfmt__.Printf("%s", yyStatname(yystate))
|
||||||
|
__yyfmt__.Printf(" saw %s\n", yyTokname(yytoken))
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case 1, 2: /* incompletely recovered error ... try again */
|
||||||
|
Errflag = 3
|
||||||
|
|
||||||
|
/* find a state where "error" is a legal shift action */
|
||||||
|
for yyp >= 0 {
|
||||||
|
yyn = yyPact[yyS[yyp].yys] + yyErrCode
|
||||||
|
if yyn >= 0 && yyn < yyLast {
|
||||||
|
yystate = yyAct[yyn] /* simulate a shift of "error" */
|
||||||
|
if yyChk[yystate] == yyErrCode {
|
||||||
|
goto yystack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the current p has no shift on "error", pop stack */
|
||||||
|
if yyDebug >= 2 {
|
||||||
|
__yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys)
|
||||||
|
}
|
||||||
|
yyp--
|
||||||
|
}
|
||||||
|
/* there is no state on the stack with an error shift ... abort */
|
||||||
|
goto ret1
|
||||||
|
|
||||||
|
case 3: /* no shift yet; clobber input char */
|
||||||
|
if yyDebug >= 2 {
|
||||||
|
__yyfmt__.Printf("error recovery discards %s\n", yyTokname(yytoken))
|
||||||
|
}
|
||||||
|
if yytoken == yyEofCode {
|
||||||
|
goto ret1
|
||||||
|
}
|
||||||
|
yyrcvr.char = -1
|
||||||
|
yytoken = -1
|
||||||
|
goto yynewstate /* try again in the same state */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reduction by production yyn */
|
||||||
|
if yyDebug >= 2 {
|
||||||
|
__yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate))
|
||||||
|
}
|
||||||
|
|
||||||
|
yynt := yyn
|
||||||
|
yypt := yyp
|
||||||
|
_ = yypt // guard against "declared and not used"
|
||||||
|
|
||||||
|
yyp -= yyR2[yyn]
|
||||||
|
// yyp is now the index of $0. Perform the default action. Iff the
|
||||||
|
// reduced production is ε, $1 is possibly out of range.
|
||||||
|
if yyp+1 >= len(yyS) {
|
||||||
|
nyys := make([]yySymType, len(yyS)*2)
|
||||||
|
copy(nyys, yyS)
|
||||||
|
yyS = nyys
|
||||||
|
}
|
||||||
|
yyVAL = yyS[yyp+1]
|
||||||
|
|
||||||
|
/* consult goto table to find next state */
|
||||||
|
yyn = yyR1[yyn]
|
||||||
|
yyg := yyPgo[yyn]
|
||||||
|
yyj := yyg + yyS[yyp].yys + 1
|
||||||
|
|
||||||
|
if yyj >= yyLast {
|
||||||
|
yystate = yyAct[yyg]
|
||||||
|
} else {
|
||||||
|
yystate = yyAct[yyj]
|
||||||
|
if yyChk[yystate] != -yyn {
|
||||||
|
yystate = yyAct[yyg]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// dummy call; replaced with literal code
|
||||||
|
switch yynt {
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
|
//line parser.go.y:43
|
||||||
|
{
|
||||||
|
yyVAL.compstmt = nil
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
yyDollar = yyS[yypt-2 : yypt+1]
|
||||||
|
//line parser.go.y:47
|
||||||
|
{
|
||||||
|
yyVAL.compstmt = yyDollar[1].stmts
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
yyDollar = yyS[yypt-2 : yypt+1]
|
||||||
|
//line parser.go.y:53
|
||||||
|
{
|
||||||
|
yyVAL.stmts = []ast.Stmt{yyDollar[2].stmt}
|
||||||
|
if l, ok := yylex.(*Lexer); ok {
|
||||||
|
l.stmts = yyVAL.stmts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
|
//line parser.go.y:60
|
||||||
|
{
|
||||||
|
if yyDollar[3].stmt != nil {
|
||||||
|
yyVAL.stmts = append(yyDollar[1].stmts, yyDollar[3].stmt)
|
||||||
|
if l, ok := yylex.(*Lexer); ok {
|
||||||
|
l.stmts = yyVAL.stmts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 5:
|
||||||
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
|
//line parser.go.y:71
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
yyVAL.stmt = &ast.ExprStmt{Expr: yyDollar[1].expr}
|
||||||
|
}
|
||||||
|
case 7:
|
||||||
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
|
//line parser.go.y:81
|
||||||
|
{
|
||||||
|
yyVAL.expr = &ast.IdentExpr{Lit: yyDollar[1].tok.Lit}
|
||||||
|
}
|
||||||
|
case 8:
|
||||||
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
|
//line parser.go.y:85
|
||||||
|
{
|
||||||
|
yyVAL.expr = &ast.NumberExpr{Lit: yyDollar[1].tok.Lit}
|
||||||
|
}
|
||||||
|
case 9:
|
||||||
|
yyDollar = yyS[yypt-2 : yypt+1]
|
||||||
|
//line parser.go.y:89
|
||||||
|
{
|
||||||
|
yyVAL.expr = &ast.UnaryExpr{Operator: "-", Expr: yyDollar[2].expr}
|
||||||
|
}
|
||||||
|
case 10:
|
||||||
|
yyDollar = yyS[yypt-2 : yypt+1]
|
||||||
|
//line parser.go.y:93
|
||||||
|
{
|
||||||
|
yyVAL.expr = &ast.UnaryExpr{Operator: "!", Expr: yyDollar[2].expr}
|
||||||
|
}
|
||||||
|
case 11:
|
||||||
|
yyDollar = yyS[yypt-2 : yypt+1]
|
||||||
|
//line parser.go.y:97
|
||||||
|
{
|
||||||
|
yyVAL.expr = &ast.UnaryExpr{Operator: "^", Expr: yyDollar[2].expr}
|
||||||
|
}
|
||||||
|
case 12:
|
||||||
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
|
//line parser.go.y:101
|
||||||
|
{
|
||||||
|
yyVAL.expr = &ast.StringExpr{Lit: yyDollar[1].tok.Lit}
|
||||||
|
}
|
||||||
|
case 13:
|
||||||
|
yyDollar = yyS[yypt-5 : yypt+1]
|
||||||
|
//line parser.go.y:105
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
yyVAL.expr = &ast.ParenExpr{SubExpr: yyDollar[2].expr}
|
||||||
|
}
|
||||||
|
case 15:
|
||||||
|
yyDollar = yyS[yypt-3 : yypt+1]
|
||||||
|
//line parser.go.y:113
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
yyVAL.expr = &ast.BinOpExpr{Lhs: yyDollar[1].expr, Operator: "&&", Rhs: yyDollar[3].expr}
|
||||||
|
}
|
||||||
|
case 32:
|
||||||
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
|
//line parser.go.y:179
|
||||||
|
{
|
||||||
|
}
|
||||||
|
case 33:
|
||||||
|
yyDollar = yyS[yypt-2 : yypt+1]
|
||||||
|
//line parser.go.y:182
|
||||||
|
{
|
||||||
|
}
|
||||||
|
case 34:
|
||||||
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
|
//line parser.go.y:187
|
||||||
|
{
|
||||||
|
}
|
||||||
|
case 35:
|
||||||
|
yyDollar = yyS[yypt-1 : yypt+1]
|
||||||
|
//line parser.go.y:190
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto yystack /* stack new state and value */
|
||||||
|
}
|
||||||
195
vendor/github.com/mattn/kinako/parser/parser.go.y
generated
vendored
Normal file
195
vendor/github.com/mattn/kinako/parser/parser.go.y
generated
vendored
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
%{
|
||||||
|
package parser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mattn/kinako/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%type<compstmt> compstmt
|
||||||
|
%type<stmts> stmts
|
||||||
|
%type<stmt> stmt
|
||||||
|
%type<expr> expr
|
||||||
|
|
||||||
|
%union{
|
||||||
|
compstmt []ast.Stmt
|
||||||
|
stmts []ast.Stmt
|
||||||
|
stmt ast.Stmt
|
||||||
|
expr ast.Expr
|
||||||
|
tok ast.Token
|
||||||
|
term ast.Token
|
||||||
|
terms ast.Token
|
||||||
|
opt_terms ast.Token
|
||||||
|
}
|
||||||
|
|
||||||
|
%token<tok> IDENT NUMBER STRING EQEQ NEQ GE LE OROR ANDAND POW
|
||||||
|
|
||||||
|
%right '='
|
||||||
|
%right '?' ':'
|
||||||
|
%left OROR
|
||||||
|
%left ANDAND
|
||||||
|
%left IDENT
|
||||||
|
%nonassoc EQEQ NEQ ','
|
||||||
|
%left '>' GE '<' LE SHIFTLEFT SHIFTRIGHT
|
||||||
|
|
||||||
|
%left '+' '-' PLUSPLUS MINUSMINUS
|
||||||
|
%left '*' '/' '%'
|
||||||
|
%right UNARY
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
compstmt : opt_terms
|
||||||
|
{
|
||||||
|
$$ = nil
|
||||||
|
}
|
||||||
|
| stmts opt_terms
|
||||||
|
{
|
||||||
|
$$ = $1
|
||||||
|
}
|
||||||
|
|
||||||
|
stmts :
|
||||||
|
opt_terms stmt
|
||||||
|
{
|
||||||
|
$$ = []ast.Stmt{$2}
|
||||||
|
if l, ok := yylex.(*Lexer); ok {
|
||||||
|
l.stmts = $$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| stmts terms stmt
|
||||||
|
{
|
||||||
|
if $3 != nil {
|
||||||
|
$$ = append($1, $3)
|
||||||
|
if l, ok := yylex.(*Lexer); ok {
|
||||||
|
l.stmts = $$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt :
|
||||||
|
expr '=' expr
|
||||||
|
{
|
||||||
|
$$ = &ast.LetStmt{Lhs: $1, Operator: "=", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr
|
||||||
|
{
|
||||||
|
$$ = &ast.ExprStmt{Expr: $1}
|
||||||
|
}
|
||||||
|
|
||||||
|
expr :
|
||||||
|
IDENT
|
||||||
|
{
|
||||||
|
$$ = &ast.IdentExpr{Lit: $1.Lit}
|
||||||
|
}
|
||||||
|
| NUMBER
|
||||||
|
{
|
||||||
|
$$ = &ast.NumberExpr{Lit: $1.Lit}
|
||||||
|
}
|
||||||
|
| '-' expr %prec UNARY
|
||||||
|
{
|
||||||
|
$$ = &ast.UnaryExpr{Operator: "-", Expr: $2}
|
||||||
|
}
|
||||||
|
| '!' expr %prec UNARY
|
||||||
|
{
|
||||||
|
$$ = &ast.UnaryExpr{Operator: "!", Expr: $2}
|
||||||
|
}
|
||||||
|
| '^' expr %prec UNARY
|
||||||
|
{
|
||||||
|
$$ = &ast.UnaryExpr{Operator: "^", Expr: $2}
|
||||||
|
}
|
||||||
|
| STRING
|
||||||
|
{
|
||||||
|
$$ = &ast.StringExpr{Lit: $1.Lit}
|
||||||
|
}
|
||||||
|
| expr '?' expr ':' expr
|
||||||
|
{
|
||||||
|
$$ = &ast.TernaryOpExpr{Expr: $1, Lhs: $3, Rhs: $5}
|
||||||
|
}
|
||||||
|
| '(' expr ')'
|
||||||
|
{
|
||||||
|
$$ = &ast.ParenExpr{SubExpr: $2}
|
||||||
|
}
|
||||||
|
| expr '+' expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "+", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr '-' expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "-", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr '*' expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "*", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr '/' expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "/", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr '%' expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "%", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr EQEQ expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "==", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr NEQ expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "!=", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr '>' expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: ">", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr GE expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: ">=", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr '<' expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "<", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr LE expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "<=", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr '|' expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "|", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr OROR expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "||", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr '&' expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "&", Rhs: $3}
|
||||||
|
}
|
||||||
|
| expr ANDAND expr
|
||||||
|
{
|
||||||
|
$$ = &ast.BinOpExpr{Lhs: $1, Operator: "&&", Rhs: $3}
|
||||||
|
}
|
||||||
|
|
||||||
|
opt_terms : /* none */
|
||||||
|
| terms
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
terms : term
|
||||||
|
{
|
||||||
|
}
|
||||||
|
| terms term
|
||||||
|
{
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
term : ';'
|
||||||
|
{
|
||||||
|
}
|
||||||
|
| '\n'
|
||||||
|
{
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
1258
vendor/github.com/mattn/kinako/parser/y.output
generated
vendored
Normal file
1258
vendor/github.com/mattn/kinako/parser/y.output
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
vendor/github.com/mattn/anko/vm/env.go → vendor/github.com/mattn/kinako/vm/env.go
generated
vendored
2
vendor/github.com/mattn/anko/vm/env.go → vendor/github.com/mattn/kinako/vm/env.go
generated
vendored
@@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/mattn/anko/parser"
|
"github.com/mattn/kinako/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Env provides interface to run VM. This mean function scope and blocked-scope.
|
// Env provides interface to run VM. This mean function scope and blocked-scope.
|
||||||
409
vendor/github.com/mattn/kinako/vm/vm.go
generated
vendored
Normal file
409
vendor/github.com/mattn/kinako/vm/vm.go
generated
vendored
Normal file
@@ -0,0 +1,409 @@
|
|||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mattn/kinako/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
NilValue = reflect.ValueOf((*interface{})(nil))
|
||||||
|
NilType = reflect.TypeOf((*interface{})(nil))
|
||||||
|
TrueValue = reflect.ValueOf(true)
|
||||||
|
FalseValue = reflect.ValueOf(false)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error provides a convenient interface for handling runtime error.
|
||||||
|
// It can be Error interface with type cast which can call Pos().
|
||||||
|
type Error struct {
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
BreakError = errors.New("Unexpected break statement")
|
||||||
|
ContinueError = errors.New("Unexpected continue statement")
|
||||||
|
ReturnError = errors.New("Unexpected return statement")
|
||||||
|
InterruptError = errors.New("Execution interrupted")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error returns the error message.
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
var err error
|
||||||
|
for _, stmt := range stmts {
|
||||||
|
rv, err = RunSingleStmt(stmt, env)
|
||||||
|
if err != nil {
|
||||||
|
return rv, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interrupts the execution of any running statements in the specified environment.
|
||||||
|
//
|
||||||
|
// Note that the execution is not instantly aborted: after a call to Interrupt,
|
||||||
|
// the current running statement will finish, but the next statement will not run,
|
||||||
|
// and instead will return a NilValue and an InterruptError.
|
||||||
|
func Interrupt(env *Env) {
|
||||||
|
env.Lock()
|
||||||
|
*(env.interrupt) = true
|
||||||
|
env.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunSingleStmt executes one statement in the specified environment.
|
||||||
|
func RunSingleStmt(stmt ast.Stmt, env *Env) (reflect.Value, error) {
|
||||||
|
env.Lock()
|
||||||
|
if *(env.interrupt) {
|
||||||
|
*(env.interrupt) = false
|
||||||
|
env.Unlock()
|
||||||
|
|
||||||
|
return NilValue, InterruptError
|
||||||
|
}
|
||||||
|
env.Unlock()
|
||||||
|
|
||||||
|
switch stmt := stmt.(type) {
|
||||||
|
case *ast.ExprStmt:
|
||||||
|
rv, err := invokeExpr(stmt.Expr, env)
|
||||||
|
if err != nil {
|
||||||
|
return rv, err
|
||||||
|
}
|
||||||
|
return rv, nil
|
||||||
|
case *ast.LetStmt:
|
||||||
|
rv := NilValue
|
||||||
|
var err error
|
||||||
|
rv, err = invokeExpr(stmt.Rhs, env)
|
||||||
|
if err != nil {
|
||||||
|
return rv, err
|
||||||
|
}
|
||||||
|
_, err = invokeLetExpr(stmt.Lhs, rv, env)
|
||||||
|
if err != nil {
|
||||||
|
return rv, err
|
||||||
|
}
|
||||||
|
return rv, nil
|
||||||
|
default:
|
||||||
|
return NilValue, errors.New("unknown statement")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// toString converts all reflect.Value-s into string.
|
||||||
|
func toString(v reflect.Value) string {
|
||||||
|
if v.Kind() == reflect.Interface {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
if v.Kind() == reflect.String {
|
||||||
|
return v.String()
|
||||||
|
}
|
||||||
|
if !v.IsValid() {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
return fmt.Sprint(v.Interface())
|
||||||
|
}
|
||||||
|
|
||||||
|
// toBool converts all reflect.Value-s into bool.
|
||||||
|
func toBool(v reflect.Value) bool {
|
||||||
|
if v.Kind() == reflect.Interface {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return v.Float() != 0.0
|
||||||
|
case reflect.Int, reflect.Int32, reflect.Int64:
|
||||||
|
return v.Int() != 0
|
||||||
|
case reflect.Bool:
|
||||||
|
return v.Bool()
|
||||||
|
case reflect.String:
|
||||||
|
if v.String() == "true" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if toInt64(v) != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// toFloat64 converts all reflect.Value-s into float64.
|
||||||
|
func toFloat64(v reflect.Value) float64 {
|
||||||
|
if v.Kind() == reflect.Interface {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return v.Float()
|
||||||
|
case reflect.Int, reflect.Int32, reflect.Int64:
|
||||||
|
return float64(v.Int())
|
||||||
|
}
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNil(v reflect.Value) bool {
|
||||||
|
if !v.IsValid() || v.Kind().String() == "unsafe.Pointer" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (v.Kind() == reflect.Interface || v.Kind() == reflect.Ptr) && v.IsNil() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNum(v reflect.Value) bool {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// equal returns true when lhsV and rhsV is same value.
|
||||||
|
func equal(lhsV, rhsV reflect.Value) bool {
|
||||||
|
lhsIsNil, rhsIsNil := isNil(lhsV), isNil(rhsV)
|
||||||
|
if lhsIsNil && rhsIsNil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (!lhsIsNil && rhsIsNil) || (lhsIsNil && !rhsIsNil) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhsV.Kind() == reflect.Interface || lhsV.Kind() == reflect.Ptr {
|
||||||
|
lhsV = lhsV.Elem()
|
||||||
|
}
|
||||||
|
if rhsV.Kind() == reflect.Interface || rhsV.Kind() == reflect.Ptr {
|
||||||
|
rhsV = rhsV.Elem()
|
||||||
|
}
|
||||||
|
if !lhsV.IsValid() || !rhsV.IsValid() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if isNum(lhsV) && isNum(rhsV) {
|
||||||
|
if rhsV.Type().ConvertibleTo(lhsV.Type()) {
|
||||||
|
rhsV = rhsV.Convert(lhsV.Type())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lhsV.CanInterface() && rhsV.CanInterface() {
|
||||||
|
return reflect.DeepEqual(lhsV.Interface(), rhsV.Interface())
|
||||||
|
}
|
||||||
|
return reflect.DeepEqual(lhsV, rhsV)
|
||||||
|
}
|
||||||
|
|
||||||
|
// toInt64 converts all reflect.Value-s into int64.
|
||||||
|
func toInt64(v reflect.Value) int64 {
|
||||||
|
if v.Kind() == reflect.Interface {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return int64(v.Float())
|
||||||
|
case reflect.Int, reflect.Int32, reflect.Int64:
|
||||||
|
return v.Int()
|
||||||
|
case reflect.String:
|
||||||
|
s := v.String()
|
||||||
|
var i int64
|
||||||
|
var err error
|
||||||
|
if strings.HasPrefix(s, "0x") {
|
||||||
|
i, err = strconv.ParseInt(s, 16, 64)
|
||||||
|
} else {
|
||||||
|
i, err = strconv.ParseInt(s, 10, 64)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
return int64(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func invokeLetExpr(expr ast.Expr, rv reflect.Value, env *Env) (reflect.Value, error) {
|
||||||
|
switch lhs := expr.(type) {
|
||||||
|
case *ast.IdentExpr:
|
||||||
|
if env.Set(lhs.Lit, rv) != nil {
|
||||||
|
if strings.Contains(lhs.Lit, ".") {
|
||||||
|
return NilValue, fmt.Errorf("Undefined symbol '%s'", lhs.Lit)
|
||||||
|
}
|
||||||
|
env.Define(lhs.Lit, rv)
|
||||||
|
}
|
||||||
|
return rv, nil
|
||||||
|
}
|
||||||
|
return NilValue, errors.New("Invalid operation")
|
||||||
|
}
|
||||||
|
|
||||||
|
// invokeExpr evaluates one expression.
|
||||||
|
func invokeExpr(expr ast.Expr, env *Env) (reflect.Value, error) {
|
||||||
|
switch e := expr.(type) {
|
||||||
|
case *ast.NumberExpr:
|
||||||
|
if strings.Contains(e.Lit, ".") || strings.Contains(e.Lit, "e") {
|
||||||
|
v, err := strconv.ParseFloat(e.Lit, 64)
|
||||||
|
if err != nil {
|
||||||
|
return NilValue, err
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(float64(v)), nil
|
||||||
|
}
|
||||||
|
var i int64
|
||||||
|
var err error
|
||||||
|
if strings.HasPrefix(e.Lit, "0x") {
|
||||||
|
i, err = strconv.ParseInt(e.Lit[2:], 16, 64)
|
||||||
|
} else {
|
||||||
|
i, err = strconv.ParseInt(e.Lit, 10, 64)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return NilValue, err
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(i), nil
|
||||||
|
case *ast.IdentExpr:
|
||||||
|
return env.Get(e.Lit)
|
||||||
|
case *ast.StringExpr:
|
||||||
|
return reflect.ValueOf(e.Lit), nil
|
||||||
|
case *ast.UnaryExpr:
|
||||||
|
v, err := invokeExpr(e.Expr, env)
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
switch e.Operator {
|
||||||
|
case "-":
|
||||||
|
if v.Kind() == reflect.Float64 {
|
||||||
|
return reflect.ValueOf(-v.Float()), nil
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(-v.Int()), nil
|
||||||
|
case "^":
|
||||||
|
return reflect.ValueOf(^toInt64(v)), nil
|
||||||
|
case "!":
|
||||||
|
return reflect.ValueOf(!toBool(v)), nil
|
||||||
|
default:
|
||||||
|
return NilValue, errors.New("Unknown operator ''")
|
||||||
|
}
|
||||||
|
case *ast.ParenExpr:
|
||||||
|
v, err := invokeExpr(e.SubExpr, env)
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
case *ast.BinOpExpr:
|
||||||
|
lhsV := NilValue
|
||||||
|
rhsV := NilValue
|
||||||
|
var err error
|
||||||
|
|
||||||
|
lhsV, err = invokeExpr(e.Lhs, env)
|
||||||
|
if err != nil {
|
||||||
|
return lhsV, err
|
||||||
|
}
|
||||||
|
if lhsV.Kind() == reflect.Interface {
|
||||||
|
lhsV = lhsV.Elem()
|
||||||
|
}
|
||||||
|
if e.Rhs != nil {
|
||||||
|
rhsV, err = invokeExpr(e.Rhs, env)
|
||||||
|
if err != nil {
|
||||||
|
return rhsV, err
|
||||||
|
}
|
||||||
|
if rhsV.Kind() == reflect.Interface {
|
||||||
|
rhsV = rhsV.Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch e.Operator {
|
||||||
|
case "+":
|
||||||
|
if lhsV.Kind() == reflect.String || rhsV.Kind() == reflect.String {
|
||||||
|
return reflect.ValueOf(toString(lhsV) + toString(rhsV)), nil
|
||||||
|
}
|
||||||
|
if (lhsV.Kind() == reflect.Array || lhsV.Kind() == reflect.Slice) && (rhsV.Kind() != reflect.Array && rhsV.Kind() != reflect.Slice) {
|
||||||
|
return reflect.Append(lhsV, rhsV), nil
|
||||||
|
}
|
||||||
|
if (lhsV.Kind() == reflect.Array || lhsV.Kind() == reflect.Slice) && (rhsV.Kind() == reflect.Array || rhsV.Kind() == reflect.Slice) {
|
||||||
|
return reflect.AppendSlice(lhsV, rhsV), nil
|
||||||
|
}
|
||||||
|
if lhsV.Kind() == reflect.Float64 || rhsV.Kind() == reflect.Float64 {
|
||||||
|
return reflect.ValueOf(toFloat64(lhsV) + toFloat64(rhsV)), nil
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(toInt64(lhsV) + toInt64(rhsV)), nil
|
||||||
|
case "-":
|
||||||
|
if lhsV.Kind() == reflect.Float64 || rhsV.Kind() == reflect.Float64 {
|
||||||
|
return reflect.ValueOf(toFloat64(lhsV) - toFloat64(rhsV)), nil
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(toInt64(lhsV) - toInt64(rhsV)), nil
|
||||||
|
case "*":
|
||||||
|
if lhsV.Kind() == reflect.String && (rhsV.Kind() == reflect.Int || rhsV.Kind() == reflect.Int32 || rhsV.Kind() == reflect.Int64) {
|
||||||
|
return reflect.ValueOf(strings.Repeat(toString(lhsV), int(toInt64(rhsV)))), nil
|
||||||
|
}
|
||||||
|
if lhsV.Kind() == reflect.Float64 || rhsV.Kind() == reflect.Float64 {
|
||||||
|
return reflect.ValueOf(toFloat64(lhsV) * toFloat64(rhsV)), nil
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(toInt64(lhsV) * toInt64(rhsV)), nil
|
||||||
|
case "/":
|
||||||
|
return reflect.ValueOf(toFloat64(lhsV) / toFloat64(rhsV)), nil
|
||||||
|
case "%":
|
||||||
|
return reflect.ValueOf(toInt64(lhsV) % toInt64(rhsV)), nil
|
||||||
|
case "==":
|
||||||
|
return reflect.ValueOf(equal(lhsV, rhsV)), nil
|
||||||
|
case "!=":
|
||||||
|
return reflect.ValueOf(equal(lhsV, rhsV) == false), nil
|
||||||
|
case ">":
|
||||||
|
return reflect.ValueOf(toFloat64(lhsV) > toFloat64(rhsV)), nil
|
||||||
|
case ">=":
|
||||||
|
return reflect.ValueOf(toFloat64(lhsV) >= toFloat64(rhsV)), nil
|
||||||
|
case "<":
|
||||||
|
return reflect.ValueOf(toFloat64(lhsV) < toFloat64(rhsV)), nil
|
||||||
|
case "<=":
|
||||||
|
return reflect.ValueOf(toFloat64(lhsV) <= toFloat64(rhsV)), nil
|
||||||
|
case "|":
|
||||||
|
return reflect.ValueOf(toInt64(lhsV) | toInt64(rhsV)), nil
|
||||||
|
case "||":
|
||||||
|
if toBool(lhsV) {
|
||||||
|
return lhsV, nil
|
||||||
|
}
|
||||||
|
return rhsV, nil
|
||||||
|
case "&":
|
||||||
|
return reflect.ValueOf(toInt64(lhsV) & toInt64(rhsV)), nil
|
||||||
|
case "&&":
|
||||||
|
if toBool(lhsV) {
|
||||||
|
return rhsV, nil
|
||||||
|
}
|
||||||
|
return lhsV, nil
|
||||||
|
case "**":
|
||||||
|
if lhsV.Kind() == reflect.Float64 {
|
||||||
|
return reflect.ValueOf(math.Pow(toFloat64(lhsV), toFloat64(rhsV))), nil
|
||||||
|
}
|
||||||
|
return reflect.ValueOf(int64(math.Pow(toFloat64(lhsV), toFloat64(rhsV)))), nil
|
||||||
|
case ">>":
|
||||||
|
return reflect.ValueOf(toInt64(lhsV) >> uint64(toInt64(rhsV))), nil
|
||||||
|
case "<<":
|
||||||
|
return reflect.ValueOf(toInt64(lhsV) << uint64(toInt64(rhsV))), nil
|
||||||
|
default:
|
||||||
|
return NilValue, errors.New("Unknown operator")
|
||||||
|
}
|
||||||
|
case *ast.TernaryOpExpr:
|
||||||
|
rv, err := invokeExpr(e.Expr, env)
|
||||||
|
if err != nil {
|
||||||
|
return rv, err
|
||||||
|
}
|
||||||
|
if toBool(rv) {
|
||||||
|
lhsV, err := invokeExpr(e.Lhs, env)
|
||||||
|
if err != nil {
|
||||||
|
return lhsV, err
|
||||||
|
}
|
||||||
|
return lhsV, nil
|
||||||
|
}
|
||||||
|
rhsV, err := invokeExpr(e.Rhs, env)
|
||||||
|
if err != nil {
|
||||||
|
return rhsV, err
|
||||||
|
}
|
||||||
|
return rhsV, nil
|
||||||
|
default:
|
||||||
|
return NilValue, errors.New("Unknown expression")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user