From 3ed24028f49fc76c01c5457963a9082f49917cf8 Mon Sep 17 00:00:00 2001 From: mappu Date: Thu, 16 Apr 2020 19:13:23 +1200 Subject: [PATCH] node: support php predefined constants --- fixtures/0011-magic-consts.php | 2 ++ main.go | 9 ++++- node.go | 62 +++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/fixtures/0011-magic-consts.php b/fixtures/0011-magic-consts.php index 1ac9340..8d8b322 100644 --- a/fixtures/0011-magic-consts.php +++ b/fixtures/0011-magic-consts.php @@ -8,6 +8,8 @@ echo __Line__; echo __DIR__; +echo PHP_INT_MAX . PHP_EOL ; + echo __NAMESPACE__; function Foo() { diff --git a/main.go b/main.go index 9874e62..99141b1 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,13 @@ import ( "php2go/parseutil" ) +const ( + phpVersionMajor = 7 + phpVersionMinor = 4 + phpVersionPatch = 0 + phpVersionExtra = `-php2go` +) + func ConvertFile(filename string) (string, error) { inputFile, err := ioutil.ReadFile(filename) @@ -27,7 +34,7 @@ func ConvertFile(filename string) (string, error) { importPackages: make(map[string]struct{}), } - p, err := parser.NewParser([]byte(inputFile), "7.4") + p, err := parser.NewParser([]byte(inputFile), fmt.Sprintf("%d.%d", phpVersionMajor, phpVersionMinor)) if err != nil { panic(err) } diff --git a/node.go b/node.go index e20eb26..e85b8e7 100644 --- a/node.go +++ b/node.go @@ -1502,7 +1502,67 @@ func (this *conversionState) convertNoFreeFloating(n_ node.Node) (string, error) return n.VarName.(*node.Identifier).Value, nil case *expr.ConstFetch: - return this.resolveName(n.Constant) + constRef, err := this.resolveName(n.Constant) + if err != nil { + return "", err + } + + // Handle PHP reserved constants + // @ref https://www.php.net/manual/en/reserved.constants.php + + if constRef == `PHP_EOL` { + // Not 100% accurate, but realistically this works on Windows too nowadays + return `"\n"`, nil + + } else if constRef == `PHP_INT_MAX` { + // Go has math.MaxInt64 in the Math package, etc + // But we don't know if this package will maybe be built on a 32-bit platform + // And we are generating plain `int` types, not necessarily int64 everywhere + + // @ref https://stackoverflow.com/a/54421330 + this.importPackages["math/bits"] = struct{}{} + return `((1 << bits.UintSize) / -2 /* INT_MAX */)`, nil + + } else if constRef == `PHP_VERSION` { + return quoteGoString(fmt.Sprintf("%d.%d.%d%s", phpVersionMajor, phpVersionMinor, phpVersionPatch, phpVersionExtra)), nil + + } else if constRef == `PHP_MAJOR_VERSION` { + return fmt.Sprintf("%d", phpVersionMajor), nil + + } else if constRef == `PHP_MINOR_VERSION` { + return fmt.Sprintf("%d", phpVersionMinor), nil + + } else if constRef == `PHP_RELEASE_VERSION` { + return fmt.Sprintf("%d", phpVersionPatch), nil + + } else if constRef == `PHP_VERSION_ID` { + return fmt.Sprintf("%d%02d%02d", phpVersionMajor, phpVersionMinor, phpVersionPatch), nil + + } else if constRef == `PHP_EXTRA_VERSION` { + return quoteGoString(phpVersionExtra), nil + + } else if constRef == `PHP_ZTS` { + return "true /* PHP_ZTS */", nil + + } else if constRef == `PHP_DEBUG` { + return "false /* PHP_DEBUG */", nil + + } else if constRef == `PHP_MAXPATHLEN` { + // Not 100% accurate + // Go filesystem functions can transparently handle long paths + // PHP on Linux has a max path of 4096 by default + // Just use that + return "4096 /* MAXPATHLEN */", nil + + } else if constRef == `PHP_OS` || constRef == `PHP_OS_FAMILY` { + // Not 100% accurate, but the right idea + this.importPackages["runtime"] = struct{}{} + return `runtime.GOOS`, nil + + } + + // No const transformation was required + return constRef, nil case *expr.Array: return this.convertArrayLiteralCommon(n.Items)