gotosocial/vendor/modernc.org/ccgo/v3/lib/go.go
tobi ebdee5aed8
[chore] Downgrade sqlite v1.29.2 -> v1.28.0 (#2736)
* [chore] Downgrade sqlite v1.29.2 -> v1.29.0

* go down to v1.28.0
2024-03-08 11:45:15 +01:00

13229 lines
406 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2020 The CCGO Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ccgo // import "modernc.org/ccgo/v3/lib"
import (
"bytes"
"fmt"
"go/scanner"
"go/token"
"hash/maphash"
"io/ioutil"
"math"
"math/big"
"os"
"os/exec"
"path/filepath"
"runtime"
"sort"
"strconv"
"strings"
"sync"
"time"
"modernc.org/cc/v3"
"modernc.org/mathutil"
)
var (
idAddOverflow = cc.String("__builtin_add_overflow") // bool __builtin_add_overflow (type1 a, type2 b, type3 *res)
idAlias = cc.String("alias")
idAligned = cc.String("aligned") // int __attribute__ ((aligned (8))) foo;
idAtomicLoadN = cc.String("__atomic_load_n") // type __atomic_load_n (type *ptr, int memorder)
idAtomicStoreN = cc.String("__atomic_store_n") // void __atomic_store_n (type *ptr, type val, int memorder)
idBp = cc.String("bp")
idBuiltinConstantPImpl = cc.String("__builtin_constant_p_impl")
idCAPI = cc.String("CAPI")
idChooseExpr = cc.String("__builtin_choose_expr")
idEnviron = cc.String("environ")
idMain = cc.String("main")
idMulOverflow = cc.String("__builtin_mul_overflow") // bool __builtin_mul_overflow (type1 a, type2 b, type3 *res)
idPacked = cc.String("packed") // __attribute__((packed))
idSubOverflow = cc.String("__builtin_sub_overflow") // bool __builtin_sub_overflow (type1 a, type2 b, type3 *res)
idTls = cc.String("tls")
idTransparentUnion = cc.String("__transparent_union__")
idTs = cc.String("ts")
idVa = cc.String("va")
idVaArg = cc.String("__ccgo_va_arg")
idVaEnd = cc.String("__ccgo_va_end")
idVaList = cc.String("va_list")
idVaStart = cc.String("__ccgo_va_start")
idWcharT = cc.String("wchar_t")
idWinWchar = cc.String("WCHAR")
idWtext = cc.String("wtext")
bytesBufferPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
oTraceG bool
oTraceW bool
oTracePin bool
)
type exprMode int
const (
doNotExport = iota
doNotChange
exportCapitalize
exportPrefix
)
const (
_ exprMode = iota
exprAddrOf // &foo as uinptr (must be static/pinned)
exprBool // foo in foo != 0
exprCondInit // foo or bar in int i = x ? foo : bar;
exprCondReturn // foo or bar in return x ? foo : bar;
exprDecay // &foo[0] in foo for array foo.
exprFunc // foo in foo(bar)
exprLValue // foo in foo = bar
exprPSelect // foo in foo->bar
exprSelect // foo in foo.bar
exprValue // foo in bar = foo
exprVoid //
exprGoPtr
)
const (
tooManyErrors = "too many errors"
)
type opKind int
const (
opNormal opKind = iota
opArray
opArrayParameter
opFunction
opUnion
opBitfield
opStruct
)
type flags byte
const (
fForceConv flags = 1 << iota
fForceNoConv
fForceRuntimeConv
fNoCondAssignment
fAddrOfFuncPtrOk
fVolatileOk
)
type imported struct {
path string // Eg. "example.com/user/foo".
name string // Eg. "foo" from "package foo".
qualifier string // Eg. "foo." or "foo2." if renamed due to name conflict.
exports map[string]struct{} // Eg. {"New": {}, "Close": {}, ...}.
used bool
}
type taggedStruct struct {
ctyp cc.Type
gotyp string
name string
node cc.Node
conflicts bool
emitted bool
}
func (s *taggedStruct) emit(p *project, ds *cc.DeclarationSpecifiers) {
if s == nil || s.emitted {
return
}
s.emitted = true
p.w("%stype %s = %s; /* %v */\n\n", tidyComment("\n", ds), s.name, s.gotyp, p.pos(s.node))
}
// Return first non empty token separator within n or dflt otherwise.
func comment(dflt string, n cc.Node) string {
if s := tokenSeparator(n); s != "" {
return s
}
return dflt
}
// tidyComment is like comment but makes comment more Go-like.
func tidyComment(dflt string, n cc.Node) (r string) { return tidyCommentString(comment(dflt, n)) }
func tidyCommentString(s string) (r string) {
defer func() {
if !strings.Contains(r, "// <blockquote><pre>") {
return
}
a := strings.Split(r, "\n")
in := false
for i, v := range a {
switch {
case in:
if strings.HasPrefix(v, "// </pre></blockquote>") {
in = false
a[i] = "//"
break
}
a[i] = fmt.Sprintf("//\t%s", v[3:])
default:
if strings.HasPrefix(v, "// <blockquote><pre>") {
a[i] = "//"
in = true
}
}
}
r = strings.Join(a, "\n")
}()
s = strings.ReplaceAll(s, "\f", "")
b := bytesBufferPool.Get().(*bytes.Buffer)
defer func() { b.Reset(); bytesBufferPool.Put(b) }()
for len(s) != 0 {
c := s[0]
s = s[1:]
if len(s) == 0 {
b.WriteByte(c)
break
}
if c != '/' {
b.WriteByte(c)
continue
}
c2 := s[0]
s = s[1:]
switch c2 {
case '/': // line comment start
b.WriteByte(c)
b.WriteByte(c2)
for {
c := s[0]
s = s[1:]
b.WriteByte(c)
if c == '\n' {
break
}
}
case '*': // block comment start
b2 := bytesBufferPool.Get().(*bytes.Buffer)
defer func() { b2.Reset(); bytesBufferPool.Put(b2) }()
for {
c := s[0]
s = s[1:]
if c != '*' {
b2.WriteByte(c)
continue
}
more:
c2 := s[0]
s = s[1:]
if c2 == '*' {
b2.WriteByte(c)
goto more
}
if c2 != '/' {
b2.WriteByte(c)
b2.WriteByte(c2)
continue
}
break
}
s2 := b2.String() // comment sans /* prefix and */ suffix
a := strings.Split(s2, "\n")
nl := len(s) != 0 && s[0] == '\n'
if len(a) == 1 { // /* foo */ form
if nl {
s = s[1:]
fmt.Fprintf(b, "//%s\n", s2)
break
}
fmt.Fprintf(b, "/*%s*/", s2)
break
}
if !nl {
fmt.Fprintf(b, "/*%s*/", s2)
break
}
// Block comment followed by a newline can be safely replaced by a sequence of
// line comments. Try to enhance the comment.
if commentForm1(b, a) ||
commentForm2(b, a) ||
commentForm3(b, a) {
break
}
// No enhancement posibilities detected, use the default form.
if a[len(a)-1] == "" {
a = a[:len(a)-1]
}
fmt.Fprintf(b, "//%s", a[0])
for _, v := range a[1:] {
fmt.Fprintf(b, "\n// %s", v)
}
default:
b.WriteByte(c)
b.WriteByte(c2)
}
}
return b.String()
}
func commentForm1(b *bytes.Buffer, a []string) bool {
// Example
//
// /*
// ** Initialize this module.
// **
// ** This Tcl module contains only a single new Tcl command named "sqlite".
// ** (Hence there is no namespace. There is no point in using a namespace
// ** if the extension only supplies one new name!) The "sqlite" command is
// ** used to open a new SQLite database. See the DbMain() routine above
// ** for additional information.
// **
// ** The EXTERN macros are required by TCL in order to work on windows.
// */
if strings.TrimSpace(a[0]) != "" {
return false
}
if strings.TrimSpace(a[len(a)-1]) != "" {
return false
}
a = a[1 : len(a)-1]
if len(a) == 0 {
return false
}
for i, v := range a {
v = strings.TrimSpace(v)
if !strings.HasPrefix(v, "*") {
return false
}
a[i] = strings.TrimLeft(v, "*")
}
fmt.Fprintf(b, "//%s", a[0])
for _, v := range a[1:] {
fmt.Fprintf(b, "\n//%s", v)
}
return true
}
func commentForm2(b *bytes.Buffer, a []string) bool {
// Example
//
// /**************************** sqlite3_column_ *******************************
// ** The following routines are used to access elements of the current row
// ** in the result set.
// */
if strings.TrimSpace(a[len(a)-1]) != "" {
return false
}
a = a[:len(a)-1]
if len(a) == 0 {
return false
}
for i, v := range a[1:] {
v = strings.TrimSpace(v)
if !strings.HasPrefix(v, "*") {
return false
}
a[i+1] = strings.TrimLeft(v, "*")
}
fmt.Fprintf(b, "// %s", strings.TrimSpace(a[0]))
if strings.HasPrefix(a[0], "**") && strings.HasSuffix(a[0], "**") {
fmt.Fprintf(b, "\n//")
}
for _, v := range a[1:] {
fmt.Fprintf(b, "\n//%s", v)
}
return true
}
func commentForm3(b *bytes.Buffer, a []string) bool {
// Example
//
// /* Call sqlite3_shutdown() once before doing anything else. This is to
// ** test that sqlite3_shutdown() can be safely called by a process before
// ** sqlite3_initialize() is. */
for i, v := range a[1:] {
v = strings.TrimSpace(v)
if !strings.HasPrefix(v, "*") {
return false
}
a[i+1] = strings.TrimLeft(v, "*")
}
fmt.Fprintf(b, "// %s", strings.TrimSpace(a[0]))
if strings.HasPrefix(a[0], "**") && strings.HasSuffix(a[0], "**") {
fmt.Fprintf(b, "\n//")
}
for _, v := range a[1:] {
fmt.Fprintf(b, "\n//%s", v)
}
return true
}
// Return the preceding white space, including any comments, of the first token
// of n.
func tokenSeparator(n cc.Node) (r string) {
if n == nil {
return ""
}
var tok cc.Token
cc.Inspect(n, func(n cc.Node, _ bool) bool {
if x, ok := n.(*cc.Token); ok {
if a, b := tok.Seq(), x.Seq(); a == 0 || a > x.Seq() && b != 0 {
tok = *x
}
}
return true
})
return tok.Sep.String()
}
func source(n ...cc.Node) (r string) {
if len(n) == 0 {
return "<nil>"
}
var a []*cc.Token
for _, v := range n {
cc.Inspect(v, func(n cc.Node, _ bool) bool {
if x, ok := n.(*cc.Token); ok && x.Seq() != 0 {
a = append(a, x)
}
return true
})
}
sort.Slice(a, func(i, j int) bool {
return a[i].Seq() < a[j].Seq()
})
w := 0
seq := -1
for _, v := range a {
if n := v.Seq(); n != seq {
seq = n
a[w] = v
w++
}
}
a = a[:w]
var b strings.Builder
for _, v := range a {
b.WriteString(v.Sep.String())
b.WriteString(v.Src.String())
}
return b.String()
}
type initPatch struct {
t cc.Type
init *cc.Initializer
fld cc.Field
}
type tld struct {
name string // Can differ from the original one.
patches []initPatch
}
type block struct {
block *cc.CompoundStatement
decls []*cc.Declaration // What to declare in this block.
params []*cc.Parameter
parent *block
scope scope
noDecl bool // Locals declared in one of the parent scopes.
topDecl bool // Declare locals at block start to avoid "jumps over declaration".
}
func newBlock(parent *block, n *cc.CompoundStatement, decls []*cc.Declaration, params []*cc.Parameter, scope scope, topDecl bool) *block {
return &block{
block: n,
decls: decls,
params: params,
parent: parent,
scope: scope,
topDecl: topDecl,
}
}
type local struct {
name string
off uintptr // If isPinned: bp+off
forceRead bool // Possibly never read.
isPinned bool // Prevent this local from being placed in Go movable stack.
}
type switchState int
const (
_ switchState = iota // Not in switch.
inSwitchFirst // Before seeing "case/default".
inSwitchCase // Seen "case/default".
inSwitchSeenBreak // In switch "case/default" and seen "break/return".
inSwitchFlat
)
type function struct {
block *block
blocks map[*cc.CompoundStatement]*block
bpName string
breakCtx int //TODO merge with continueCtx
complits map[*cc.PostfixExpression]uintptr
condInitPrefix func()
continueCtx int
flatLabels int
flatSwitchLabels map[*cc.LabeledStatement]int
fndef *cc.FunctionDefinition
gen *project
ifCtx cc.Node
ignore map[*cc.Declarator]bool // Pseudo declarators
labelNames map[cc.StringID]string
labels scope
locals map[*cc.Declarator]*local
off uintptr // bp+off allocs
params []*cc.Parameter // May differ from what fndef says
project *project
rt cc.Type // May differ from what fndef says
scope scope
switchCtx switchState
tlsName string
top *block
unusedLabels map[cc.StringID]struct{}
vaLists map[*cc.PostfixExpression]uintptr
vaName string
vaType cc.Type
vlas map[*cc.Declarator]struct{}
hasJumps bool
mainSignatureForced bool
}
func newFunction(p *project, n *cc.FunctionDefinition) *function {
d := n.Declarator
t := d.Type()
rt := t.Result()
params := t.Parameters()
var mainSignatureForced bool
var ignore map[*cc.Declarator]bool
if d.Name() == idMain && d.Linkage == cc.External {
if rt.Kind() != cc.Int {
rt = p.task.cfg.ABI.Type(cc.Int)
}
if len(params) != 2 {
mainSignatureForced = true
d1 := newDeclarator("argc")
t1 := p.task.cfg.ABI.Type(cc.Int)
d2 := newDeclarator("argv")
t2 := p.task.cfg.ABI.Ptr(n, p.task.cfg.ABI.Type(cc.Void))
params = []*cc.Parameter{
cc.NewParameter(d1, t1),
cc.NewParameter(d2, t2),
}
ignore = map[*cc.Declarator]bool{d1: true, d2: true}
}
}
f := &function{
blocks: map[*cc.CompoundStatement]*block{},
complits: map[*cc.PostfixExpression]uintptr{},
fndef: n,
gen: p,
hasJumps: n.CompoundStatement.IsJumpTarget(),
ignore: ignore,
locals: map[*cc.Declarator]*local{},
mainSignatureForced: mainSignatureForced,
params: params,
project: p,
rt: rt,
scope: p.newScope(),
unusedLabels: map[cc.StringID]struct{}{},
vaLists: map[*cc.PostfixExpression]uintptr{},
vlas: map[*cc.Declarator]struct{}{},
}
f.tlsName = f.scope.take(idTls)
if t.IsVariadic() {
f.vaName = f.scope.take(idVa)
}
f.layoutLocals(nil, n.CompoundStatement, params)
var extern []cc.StringID
for _, v := range n.CompoundStatements() { // testdata/gcc-9.1.0/gcc/testsuite/gcc.c-torture/execute/scope-1.c
for _, v := range v.Declarations() {
for list := v.InitDeclaratorList; list != nil; list = list.InitDeclaratorList {
if d := list.InitDeclarator.Declarator; d != nil && d.IsExtern() {
extern = append(extern, d.Name())
}
}
}
}
for _, v := range n.CompoundStatements() {
block := f.blocks[v]
for _, v := range extern {
if tld := f.project.externs[v]; tld != nil {
block.scope.take(cc.String(tld.name))
}
}
}
for _, v := range n.CompoundStatements() {
f.layoutBlocks(v)
}
f.renameLabels()
f.staticAllocsAndPinned(n.CompoundStatement)
return f
}
func (f *function) flatLabel() int {
if f.project.pass1 {
return 1
}
f.flatLabels++
return f.flatLabels
}
func (f *function) renameLabels() {
var a []cc.StringID
for _, v := range f.fndef.Labels {
if v.Case != cc.LabeledStatementLabel {
continue
}
a = append(a, v.Token.Value)
f.unusedLabels[v.Token.Value] = struct{}{}
}
for _, v := range f.fndef.Gotos {
delete(f.unusedLabels, v.Token2.Value)
}
if len(a) == 0 {
return
}
sort.Slice(a, func(i, j int) bool { return a[i].String() < a[j].String() })
f.labels = newScope()
f.labelNames = map[cc.StringID]string{}
for _, id := range a {
f.labelNames[id] = f.labels.take(id)
}
}
func (f *function) staticAllocsAndPinned(n *cc.CompoundStatement) {
for _, v := range f.params {
switch {
case v.Type().Kind() == cc.Array && v.Type().IsVLA():
// trc("VLA")
f.project.err(f.fndef, "variable length arrays not supported")
}
}
//TODO use pass1 for this
cc.Inspect(n, func(n cc.Node, entry bool) bool {
if !entry {
return true
}
switch x := n.(type) {
case *cc.CastExpression:
switch x.Case {
case cc.CastExpressionCast: // '(' TypeName ')' CastExpression
if t := x.TypeName.Type(); t != nil && t.Kind() != cc.Void {
break
}
if d := x.CastExpression.Declarator(); d != nil {
if local := f.locals[d]; local != nil {
local.forceRead = true
}
}
}
}
x, ok := n.(*cc.PostfixExpression)
if !ok || x.Case != cc.PostfixExpressionCall {
return true
}
if x.PostfixExpression == nil || x.PostfixExpression.Operand == nil || x.PostfixExpression.Operand.Type() == nil {
return true
}
ft := funcType(x.PostfixExpression.Operand.Type())
if ft.Kind() != cc.Function {
return true
}
if !ft.IsVariadic() {
return true
}
fixedParams := len(ft.Parameters())
iArg := 0
var need uintptr
for list := x.ArgumentExpressionList; list != nil; list, iArg = list.ArgumentExpressionList, iArg+1 {
if iArg < fixedParams {
continue
}
t := list.AssignmentExpression.Operand.Type()
if t.IsIntegerType() {
need += 8
continue
}
switch t.Kind() {
case cc.Array, cc.Ptr, cc.Double, cc.Float, cc.Function:
need += 8
default:
panic(todo("", f.project.pos(x), t, t.Kind()))
}
}
if need != 0 {
//TODO- if f.project.task.mingw {
//TODO- need += 8 // On windows the va list is prefixed with its length
//TODO- }
va := roundup(f.off, 8)
f.vaLists[x] = va
f.off = va + need
}
return true
})
}
func funcType(t cc.Type) cc.Type {
if t.Kind() == cc.Ptr {
t = t.Elem()
}
return t
}
type declarator interface {
Declarator() *cc.Declarator
cc.Node
}
func (p *project) isArrayParameterDeclarator(d *cc.Declarator) bool {
if d.Type().Kind() == cc.Array {
if d.Type().IsVLA() {
return false
}
return d.IsParameter
}
return false
}
func (p *project) isArrayDeclarator(d *cc.Declarator) bool {
if d.Type().Kind() == cc.Array {
if d.Type().IsVLA() {
return false
}
return !d.IsParameter
}
return false
}
func (p *project) isArrayParameter(n declarator, t cc.Type) bool {
if t.Kind() != cc.Array {
return false
}
if t.IsVLA() {
return false
}
if d := n.Declarator(); d != nil {
return d.IsParameter
}
return false
}
func (p *project) isArrayOrPinnedArray(f *function, n declarator, t cc.Type) (r bool) {
if t.Kind() != cc.Array {
return false
}
if t.IsVLA() {
return false
}
if d := n.Declarator(); d != nil {
return !d.IsParameter
}
return p.detectArray(f, n.(cc.Node), true, true, nil)
}
func (p *project) detectArray(f *function, n cc.Node, pinnedOk, recursiveOk bool, out **cc.Declarator) bool {
switch x := n.(type) {
case *cc.AssignmentExpression:
switch x.Case {
case cc.AssignmentExpressionCond: // ConditionalExpression
return p.detectArray(f, x.ConditionalExpression, pinnedOk, recursiveOk, out)
case cc.AssignmentExpressionAssign: // UnaryExpression '=' AssignmentExpression
return p.detectArray(f, x.UnaryExpression, pinnedOk, recursiveOk, out)
default:
return false
}
case *cc.ConditionalExpression:
switch x.Case {
case cc.ConditionalExpressionLOr: // LogicalOrExpression
return p.detectArray(f, x.LogicalOrExpression, pinnedOk, recursiveOk, out)
case cc.ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression
return p.detectArray(f, x.LogicalOrExpression, pinnedOk, recursiveOk, out) ||
p.detectArray(f, x.Expression, pinnedOk, recursiveOk, out) ||
p.detectArray(f, x.ConditionalExpression, pinnedOk, recursiveOk, out)
default:
panic(todo("", p.pos(x), x.Case))
}
case *cc.LogicalOrExpression:
switch x.Case {
case cc.LogicalOrExpressionLAnd: // LogicalAndExpression
return p.detectArray(f, x.LogicalAndExpression, pinnedOk, recursiveOk, out)
default:
return false
}
case *cc.LogicalAndExpression:
switch x.Case {
case cc.LogicalAndExpressionOr: // InclusiveOrExpression
return p.detectArray(f, x.InclusiveOrExpression, pinnedOk, recursiveOk, out)
default:
return false
}
case *cc.InclusiveOrExpression:
switch x.Case {
case cc.InclusiveOrExpressionXor: // ExclusiveOrExpression
return p.detectArray(f, x.ExclusiveOrExpression, pinnedOk, recursiveOk, out)
default:
return false
}
case *cc.ExclusiveOrExpression:
switch x.Case {
case cc.ExclusiveOrExpressionAnd: // AndExpression
return p.detectArray(f, x.AndExpression, pinnedOk, recursiveOk, out)
default:
return false
}
case *cc.AndExpression:
switch x.Case {
case cc.AndExpressionEq: // EqualityExpression
return p.detectArray(f, x.EqualityExpression, pinnedOk, recursiveOk, out)
default:
return false
}
case *cc.EqualityExpression:
switch x.Case {
case cc.EqualityExpressionRel: // RelationalExpression
return p.detectArray(f, x.RelationalExpression, pinnedOk, recursiveOk, out)
default:
return false
}
case *cc.RelationalExpression:
switch x.Case {
case cc.RelationalExpressionShift: // ShiftExpression
return p.detectArray(f, x.ShiftExpression, pinnedOk, recursiveOk, out)
default:
return false
}
case *cc.ShiftExpression:
switch x.Case {
case cc.ShiftExpressionAdd: // AdditiveExpression
return p.detectArray(f, x.AdditiveExpression, pinnedOk, recursiveOk, out)
default:
return false
}
case *cc.AdditiveExpression:
switch x.Case {
case cc.AdditiveExpressionMul: // MultiplicativeExpression
return p.detectArray(f, x.MultiplicativeExpression, pinnedOk, recursiveOk, out)
case
cc.AdditiveExpressionSub, // AdditiveExpression '-' MultiplicativeExpression
cc.AdditiveExpressionAdd: // AdditiveExpression '+' MultiplicativeExpression
return p.detectArray(f, x.AdditiveExpression, pinnedOk, recursiveOk, out) || p.detectArray(f, x.MultiplicativeExpression, pinnedOk, recursiveOk, out)
default:
panic(todo("", p.pos(x), x.Case))
}
case *cc.MultiplicativeExpression:
switch x.Case {
case cc.MultiplicativeExpressionCast: // CastExpression
return p.detectArray(f, x.CastExpression, pinnedOk, recursiveOk, out)
default:
return false
}
case *cc.CastExpression:
switch x.Case {
case cc.CastExpressionUnary: // UnaryExpression
return p.detectArray(f, x.UnaryExpression, pinnedOk, recursiveOk, out)
case cc.CastExpressionCast: // '(' TypeName ')' CastExpression
return p.detectArray(f, x.CastExpression, pinnedOk, recursiveOk, out)
default:
panic(todo("", p.pos(x), x.Case))
}
case *cc.UnaryExpression:
switch x.Case {
case cc.UnaryExpressionPostfix: // PostfixExpression
return p.detectArray(f, x.PostfixExpression, pinnedOk, recursiveOk, out)
case
cc.UnaryExpressionDeref, // '*' CastExpression
cc.UnaryExpressionAddrof: // '&' CastExpression
return p.detectArray(f, x.CastExpression, pinnedOk, recursiveOk, out)
case
cc.UnaryExpressionSizeofExpr, // "sizeof" UnaryExpression
cc.UnaryExpressionSizeofType, // "sizeof" '(' TypeName ')'
cc.UnaryExpressionMinus, // '-' CastExpression
cc.UnaryExpressionCpl, // '~' CastExpression
cc.UnaryExpressionAlignofExpr, // "_Alignof" UnaryExpression
cc.UnaryExpressionAlignofType, // "_Alignof" '(' TypeName ')'
cc.UnaryExpressionNot, // '!' CastExpression
cc.UnaryExpressionInc, // "++" UnaryExpression
cc.UnaryExpressionDec, // "--" UnaryExpression
cc.UnaryExpressionPlus: // '+' CastExpression
return false
default:
panic(todo("", p.pos(x), x.Case))
}
case *cc.PostfixExpression:
switch x.Case {
case cc.PostfixExpressionPrimary: // PrimaryExpression
return p.detectArray(f, x.PrimaryExpression, pinnedOk, recursiveOk, out)
case cc.PostfixExpressionIndex: // PostfixExpression '[' Expression ']'
return recursiveOk && p.detectArray(f, x.PostfixExpression, pinnedOk, recursiveOk, out)
case
cc.PostfixExpressionSelect, // PostfixExpression '.' IDENTIFIER
cc.PostfixExpressionDec, // PostfixExpression "--"
cc.PostfixExpressionInc, // PostfixExpression "++"
cc.PostfixExpressionCall, // PostfixExpression '(' ArgumentExpressionList ')'
cc.PostfixExpressionComplit, // '(' TypeName ')' '{' InitializerList ',' '}'
cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
return false
default:
panic(todo("", p.pos(x), x.Case))
}
case *cc.PrimaryExpression:
switch x.Case {
case
cc.PrimaryExpressionString, // STRINGLITERAL
cc.PrimaryExpressionEnum, // ENUMCONST
cc.PrimaryExpressionChar, // CHARCONST
cc.PrimaryExpressionLChar, // LONGCHARCONST
cc.PrimaryExpressionLString, // LONGSTRINGLITERAL
cc.PrimaryExpressionFloat, // FLOATCONST
cc.PrimaryExpressionInt: // INTCONST
return false
case cc.PrimaryExpressionIdent: // IDENTIFIER
d := x.Declarator()
if d == nil || d.IsParameter {
return false
}
if d.Type().Kind() != cc.Array {
return false
}
if d.Type().IsVLA() {
return false
}
if pinnedOk {
if out != nil {
*out = d
}
return true
}
local := f.locals[d]
if local == nil || local.isPinned {
return false
}
if out != nil {
*out = d
}
return true
case cc.PrimaryExpressionExpr: // '(' Expression ')'
return p.detectArray(f, x.Expression, pinnedOk, recursiveOk, out)
case cc.PrimaryExpressionStmt: // '(' CompoundStatement ')'
p.err(x, "statement expressions not supported")
return false
default:
panic(todo("", p.pos(x), x.Case))
}
case *cc.Expression:
switch x.Case {
case cc.ExpressionAssign: // AssignmentExpression
return p.detectArray(f, x.AssignmentExpression, pinnedOk, recursiveOk, out)
case cc.ExpressionComma: // Expression ',' AssignmentExpression
return p.detectArray(f, x.Expression, pinnedOk, recursiveOk, out) || p.detectArray(f, x.AssignmentExpression, pinnedOk, recursiveOk, out)
default:
panic(todo("", p.pos(x), x.Case))
}
default:
panic(todo("%T", x))
}
}
func (p *project) isArray(f *function, n declarator, t cc.Type) (r bool) {
if t.Kind() != cc.Array {
return false
}
if t.IsVLA() {
return false
}
if f == nil {
return true
}
if d := n.Declarator(); d != nil {
local := f.locals[d]
return !d.IsParameter && (local == nil || !local.isPinned)
}
return p.detectArray(f, n.(cc.Node), false, true, nil)
}
var home = os.Getenv("HOME")
// Return n's position with path reduced to baseName(path) unless
// p.task.fullPathComments is true.
func (p *project) pos(n cc.Node) (r token.Position) {
if n == nil {
return r
}
if r = token.Position(n.Position()); r.IsValid() {
switch {
case p.task.fullPathComments:
if strings.HasPrefix(r.Filename, home) {
r.Filename = "$HOME" + r.Filename[len(home):]
}
default:
r.Filename = filepath.Base(r.Filename)
}
}
return r
}
// Return n's position with path reduced to baseName(path).
func pos(n cc.Node) (r token.Position) {
if n == nil {
return r
}
r = token.Position(n.Position())
if r.IsValid() {
r.Filename = filepath.Base(r.Filename)
}
return r
}
func roundup(n, to uintptr) uintptr {
if r := n % to; r != 0 {
return n + to - r
}
return n
}
func (f *function) pin(n cc.Node, d *cc.Declarator) {
local := f.locals[d]
if local == nil || local.isPinned {
return
}
local.isPinned = true
if oTracePin || f.project.task.tracePinning {
fmt.Printf("%v: %s at %v: is pinned (%v)\n", n.Position(), d.Name(), d.Position(), origin(2))
}
local.off = roundup(f.off, uintptr(d.Type().Align()))
f.off = local.off + paramTypeDecay(d).Size()
}
func paramTypeDecay(d *cc.Declarator) (r cc.Type) {
r = d.Type()
if d.IsParameter && r.Kind() == cc.Array {
r = r.Decay()
}
return r
}
func (f *function) layoutBlocks(n *cc.CompoundStatement) {
block := f.blocks[n]
type item struct {
ds *cc.DeclarationSpecifiers
d *cc.Declarator
}
var work []item
for _, v := range block.params {
if v.Type().Kind() == cc.Void {
break
}
work = append(work, item{nil, v.Declarator()})
}
for _, decl := range block.decls {
ds := decl.DeclarationSpecifiers
for list := decl.InitDeclaratorList; list != nil; list = list.InitDeclaratorList {
work = append(work, item{ds, list.InitDeclarator.Declarator})
}
}
block.scope.take(cc.String(f.tlsName))
if f.vaName != "" {
block.scope.take(cc.String(f.vaName))
}
for _, item := range work {
d := item.d
if f.ignore[d] {
continue
}
if !f.ignore[d] && d.IsStatic() {
continue
}
if d.IsFunctionPrototype() || d.IsExtern() {
continue
}
local := &local{forceRead: d.Read == 0}
if t := d.Type(); t != nil && t.Name() == idVaList {
local.forceRead = true
}
f.locals[d] = local
local.name = block.scope.take(d.Name())
}
}
func (f *function) layoutLocals(parent *block, n *cc.CompoundStatement, params []*cc.Parameter) {
block := newBlock(parent, n, n.Declarations(), params, f.project.newScope(), n.IsJumpTarget())
f.blocks[n] = block
if parent == nil {
f.top = block
f.top.topDecl = f.hasJumps
}
for _, ch := range n.Children() {
f.layoutLocals(block, ch, nil)
if f.hasJumps {
chb := f.blocks[ch]
chb.noDecl = true
f.top.decls = append(f.top.decls, chb.decls...)
chb.decls = nil
}
}
}
func newDeclarator(name string) *cc.Declarator {
return &cc.Declarator{
DirectDeclarator: &cc.DirectDeclarator{
Case: cc.DirectDeclaratorIdent,
Token: cc.Token{Rune: cc.IDENTIFIER, Value: cc.String(name)},
},
}
}
type enumSpec struct {
decl *cc.Declaration
spec *cc.EnumSpecifier
emitted bool
}
func (n *enumSpec) emit(p *project) {
if n == nil || p.pass1 || n.emitted {
return
}
n.emitted = true
ok := false
for list := n.spec.EnumeratorList; list != nil; list = list.EnumeratorList {
nm := list.Enumerator.Token.Value
if _, ok2 := p.emitedEnums[nm]; !ok2 && p.enumConsts[nm] != "" {
ok = true
break
}
}
if !ok {
return
}
p.w("%s", tidyComment("\n", n.decl))
p.w("const ( /* %v: */", p.pos(n.decl))
for list := n.spec.EnumeratorList; list != nil; list = list.EnumeratorList {
en := list.Enumerator
nm := en.Token.Value
if _, ok := p.emitedEnums[nm]; ok || p.enumConsts[nm] == "" {
continue
}
p.emitedEnums[nm] = struct{}{}
p.w("%s%s = ", tidyComment("\n", en), p.enumConsts[nm])
p.intConst(en, "", en.Operand, en.Operand.Type(), fForceNoConv)
p.w(";")
}
p.w(");")
}
type typedef struct {
sig uint64
tld *tld
}
type define struct {
name string
value cc.Value
}
type project struct {
ast *cc.AST
buf bytes.Buffer
capi []string
defines map[cc.StringID]define
defineLines []string
emitedEnums map[cc.StringID]struct{}
enumConsts map[cc.StringID]string
enumSpecs map[*cc.EnumSpecifier]*enumSpec
errors scanner.ErrorList
externs map[cc.StringID]*tld
fn string
imports map[string]*imported // C name: import info
intType cc.Type
localTaggedStructs []func()
mainName string
ptrSize uintptr
ptrType cc.Type
scope scope
sharedFns map[*cc.FunctionDefinition]struct{}
sharedFnsEmitted map[*cc.FunctionDefinition]struct{}
staticQueue []*cc.InitDeclarator
structs map[cc.StringID]*taggedStruct // key: C tag
symtab map[string]interface{} // *tld or *imported
task *Task
tldScope scope
tlds map[*cc.Declarator]*tld
ts bytes.Buffer // Text segment
tsName string
tsNameP string
tsOffs map[cc.StringID]uintptr
tsW []rune // Text segment, wchar_t
tsWName string
tsWNameP string
tsWOffs map[cc.StringID]uintptr
typeSigHash maphash.Hash
typedefTypes map[cc.StringID]*typedef
typedefsEmited map[string]struct{}
verifyStructs map[string]cc.Type
wanted map[*cc.Declarator]struct{}
wcharSize uintptr
isMain bool
pass1 bool
pauseCodegen bool
}
func newProject(t *Task) (*project, error) {
voidType := t.cfg.ABI.Type(cc.Void)
ptrType := t.cfg.ABI.Ptr(nil, voidType)
intType := t.cfg.ABI.Type(cc.Int)
if intType.Size() != 4 { // We're assuming wchar_t is int32.
return nil, fmt.Errorf("unsupported C int size: %d", intType.Size())
}
if n := t.cfg.ABI.Types[cc.UChar].Size; n != 1 {
return nil, fmt.Errorf("unsupported C unsigned char size: %d", n)
}
if n := t.cfg.ABI.Types[cc.UShort].Size; n != 2 {
return nil, fmt.Errorf("unsupported C unsigned short size: %d", n)
}
if n := t.cfg.ABI.Types[cc.UInt].Size; n != 4 {
return nil, fmt.Errorf("unsupported C unsigned int size: %d", n)
}
if n := t.cfg.ABI.Types[cc.ULongLong].Size; n != 8 {
return nil, fmt.Errorf("unsupported C unsigned long long size: %d", n)
}
p := &project{
defines: map[cc.StringID]define{},
emitedEnums: map[cc.StringID]struct{}{},
enumConsts: map[cc.StringID]string{},
enumSpecs: map[*cc.EnumSpecifier]*enumSpec{},
externs: map[cc.StringID]*tld{},
imports: map[string]*imported{},
intType: intType,
ptrSize: t.cfg.ABI.Types[cc.Ptr].Size,
ptrType: ptrType,
scope: newScope(),
sharedFns: t.cfg.SharedFunctionDefinitions.M,
sharedFnsEmitted: map[*cc.FunctionDefinition]struct{}{},
symtab: map[string]interface{}{},
task: t,
tlds: map[*cc.Declarator]*tld{},
tsWOffs: map[cc.StringID]uintptr{},
tsOffs: map[cc.StringID]uintptr{},
typedefTypes: map[cc.StringID]*typedef{},
typedefsEmited: map[string]struct{}{},
verifyStructs: map[string]cc.Type{},
wanted: map[*cc.Declarator]struct{}{},
wcharSize: t.asts[0].WideCharType.Size(),
}
p.tldScope = p.scope
p.scope.take(idCAPI)
for _, v := range t.imported {
var err error
if v.name, v.exports, err = t.capi(v.path); err != nil {
return nil, err
}
v.qualifier = p.scope.take(cc.String(v.name)) + "."
for k := range v.exports {
if p.imports[k] == nil {
p.imports[k] = v
}
}
}
p.tsNameP = p.scope.take(idTs)
p.tsName = p.scope.take(idTs)
p.tsWNameP = p.scope.take(idWtext)
p.tsWName = p.scope.take(idWtext)
if err := p.layout(); err != nil {
return nil, err
}
return p, nil
}
func (p *project) newScope() scope {
s := newScope()
var a []cc.StringID
for k := range p.structs {
a = append(a, k)
}
sort.Slice(a, func(i, j int) bool { return a[i].String() < a[j].String() })
for _, k := range a {
s.take(cc.String(p.structs[k].name))
}
return s
}
func (p *project) err(n cc.Node, s string, args ...interface{}) {
if p.task.errTrace || strings.Contains(s, "internal error") {
s = s + "(" + origin(2) + ")"
}
if p.task.traceTranslationUnits {
trc("%v: error: %s (%v)", pos(n), fmt.Sprintf(s, args...), origin(2))
}
if !p.task.allErrors && len(p.errors) >= 10 {
return
}
switch {
case n == nil:
p.errors.Add(token.Position{}, fmt.Sprintf(s, args...))
default:
p.errors.Add(token.Position(n.Position()), fmt.Sprintf(s, args...))
if !p.task.allErrors && len(p.errors) == 10 {
p.errors.Add(token.Position(n.Position()), tooManyErrors)
}
}
}
func (p *project) o(s string, args ...interface{}) {
if oTraceG {
fmt.Printf(s, args...)
}
fmt.Fprintf(p.task.out, s, args...)
}
func (p *project) w(s string, args ...interface{}) {
if p.pass1 || p.pauseCodegen {
return
}
if coverExperiment {
pc, _, _, ok := runtime.Caller(1)
if ok {
coverMap[pc] = struct{}{}
}
}
if oTraceW {
fmt.Printf(s, args...)
}
//fmt.Fprintf(&p.buf, "/* %s */", origin(2)) //TODO-
fmt.Fprintf(&p.buf, s, args...)
}
func (p *project) layout() error {
if err := p.layoutTLDs(); err != nil {
return err
}
if err := p.layoutSymtab(); err != nil {
return err
}
if err := p.layoutStructs(); err != nil {
return err
}
if err := p.layoutEnums(); err != nil {
return err
}
if err := p.layoutDefines(); err != nil {
return err
}
return p.layoutStaticLocals()
}
func (p *project) layoutSymtab() error {
var t0 time.Time
if p.task.traceTranslationUnits {
fmt.Printf("processing symbol table ... ")
t0 = time.Now()
defer func() { fmt.Println(time.Since(t0)) }()
}
for _, i := range p.task.symSearchOrder {
switch {
case i < 0:
imported := p.task.imported[-i-1]
for nm := range imported.exports {
if _, ok := p.symtab[nm]; !ok {
p.symtab[nm] = imported
}
}
default:
ast := p.task.asts[i]
for d := range ast.TLD {
if d.IsFunctionPrototype() || d.Linkage != cc.External {
continue
}
nm := d.Name()
name := nm.String()
if _, ok := p.symtab[name]; !ok {
tld := p.externs[nm]
if tld == nil {
if d.Type().Kind() != cc.Function && !p.task.header {
p.err(d, "back-end: undefined: %s %v %v", d.Name(), d.Type(), d.Type().Kind())
}
continue
}
p.symtab[name] = tld
}
}
}
}
return nil
}
func (p *project) layoutDefines() error {
if !p.task.exportDefinesValid {
return nil
}
var t0 time.Time
if p.task.traceTranslationUnits {
fmt.Printf("processing #defines ... ")
t0 = time.Now()
defer func() { fmt.Println(time.Since(t0)) }()
}
var prefix = p.task.exportDefines
taken := map[cc.StringID]struct{}{}
for _, ast := range p.task.asts {
var a []cc.StringID
for nm, m := range ast.Macros {
if m.IsFnLike() {
continue
}
if strings.HasPrefix(nm.String(), "__") {
continue
}
if _, ok := taken[nm]; ok {
continue
}
taken[nm] = struct{}{}
a = append(a, nm)
}
sort.Slice(a, func(i, j int) bool { return a[i].String() < a[j].String() })
for _, nm := range a {
m := ast.Macros[nm]
val, src := evalMacro(m, ast)
if src == "" {
continue
}
name := nm.String()
switch {
case prefix == "":
name = capitalize(name)
default:
name = prefix + name
}
name = p.scope.take(cc.String(name))
p.defines[nm] = define{name, val}
p.defineLines = append(p.defineLines, fmt.Sprintf("%s = %s // %v:", name, src, p.pos(m)))
}
}
return nil
}
func evalMacro(m *cc.Macro, ast *cc.AST) (cc.Value, string) {
toks := m.ReplacementTokens()
if len(toks) != 1 {
return evalMacro2(m, ast)
}
src := strings.TrimSpace(toks[0].Src.String())
if len(src) == 0 {
return nil, ""
}
neg := ""
switch src[0] {
case '"':
if _, err := strconv.Unquote(src); err == nil {
return cc.StringValue(cc.String(src)), src
}
case '-':
neg = "-"
src = src[1:]
fallthrough
default:
src = strings.TrimRight(src, "lLuU")
if u64, err := strconv.ParseUint(src, 0, 64); err == nil {
switch {
case neg == "":
return cc.Uint64Value(u64), src
default:
return cc.Int64Value(-u64), neg + src
}
}
src = strings.TrimRight(src, "fF")
if f64, err := strconv.ParseFloat(src, 64); err == nil {
return cc.Float64Value(f64), neg + src
}
}
return evalMacro2(m, ast)
}
func evalMacro2(m *cc.Macro, ast *cc.AST) (cc.Value, string) {
op, err := ast.Eval(m)
if err != nil {
return nil, ""
}
switch x := op.Value().(type) {
case cc.Int64Value:
return op.Value(), fmt.Sprintf("%d", int64(x))
case cc.Uint64Value:
return op.Value(), fmt.Sprintf("%d", uint64(x))
default:
panic(todo("", pos(m)))
}
}
func (p *project) layoutEnums() error {
var t0 time.Time
if p.task.traceTranslationUnits {
fmt.Printf("processing enum values ... ")
t0 = time.Now()
defer func() { fmt.Println(time.Since(t0)) }()
}
export := doNotChange
if p.task.exportEnumsValid {
switch {
case p.task.exportEnums != "":
export = exportPrefix
default:
export = exportCapitalize
}
} else if p.task.defaultUnExport {
export = doNotExport
}
var enumList []*cc.EnumSpecifier
for _, v := range p.task.asts {
for list := v.TranslationUnit; list != nil; list = list.TranslationUnit {
decl := list.ExternalDeclaration
switch decl.Case {
case cc.ExternalDeclarationDecl: // Declaration
// ok
default:
continue
}
cc.Inspect(decl.Declaration.DeclarationSpecifiers, func(n cc.Node, entry bool) bool {
if !entry {
return true
}
x, ok := n.(*cc.EnumSpecifier)
if !ok || x.Case != cc.EnumSpecifierDef {
return true
}
if _, ok := p.enumSpecs[x]; !ok {
enumList = append(enumList, x)
p.enumSpecs[x] = &enumSpec{decl: decl.Declaration, spec: x}
}
return true
})
}
}
vals := map[cc.StringID]interface{}{}
for _, v := range enumList {
for list := v.EnumeratorList; list != nil; list = list.EnumeratorList {
en := list.Enumerator
nm := en.Token.Value
var val int64
switch x := en.Operand.Value().(type) {
case cc.Int64Value:
val = int64(x)
case cc.Uint64Value:
val = int64(x)
default:
panic(todo(""))
}
switch ex, ok := vals[nm]; {
case ok:
switch {
case ex == nil: //
continue
case ex == val: // same name and same value
continue
default: // same name, different value
vals[nm] = nil
}
default:
vals[nm] = val
}
p.enumConsts[nm] = ""
}
}
var a []cc.StringID
for nm := range p.enumConsts {
if val, ok := vals[nm]; ok && val == nil {
delete(p.enumConsts, nm)
continue
}
a = append(a, nm)
}
sort.Slice(a, func(i, j int) bool { return a[i].String() < a[j].String() })
for _, nm := range a {
name := nm.String()
switch export {
case doNotExport:
name = unCapitalize(name)
case doNotChange:
// nop
case exportCapitalize:
name = capitalize(name)
case exportPrefix:
name = p.task.exportEnums + name
}
name = p.scope.take(cc.String(name))
p.enumConsts[nm] = name
}
return nil
}
func (p *project) layoutStaticLocals() error {
var t0 time.Time
if p.task.traceTranslationUnits {
fmt.Printf("processing static local declarations ... ")
t0 = time.Now()
defer func() { fmt.Println(time.Since(t0)) }()
}
for _, v := range p.task.asts {
for list := v.TranslationUnit; list != nil; list = list.TranslationUnit {
decl := list.ExternalDeclaration
switch decl.Case {
case cc.ExternalDeclarationFuncDef: // FunctionDefinition
// ok
default:
continue
}
cc.Inspect(decl.FunctionDefinition.CompoundStatement, func(n cc.Node, entry bool) bool {
switch x := n.(type) {
case *cc.Declarator:
if !entry || !x.IsStatic() || x.Read == 0 || x.IsParameter {
break
}
nm := x.Name()
if s := p.task.staticLocalsPrefix; s != "" {
nm = cc.String(s + nm.String())
}
p.tlds[x] = &tld{name: p.scope.take(nm)}
}
return true
})
}
}
return nil
}
func (p *project) layoutStructs() error {
var t0 time.Time
if p.task.traceTranslationUnits {
fmt.Printf("processing struct/union types ... ")
t0 = time.Now()
defer func() { fmt.Println(time.Since(t0)) }()
}
export := doNotChange
if p.task.exportStructsValid {
switch {
case p.task.exportStructs != "":
export = exportPrefix
default:
export = exportCapitalize
}
} else if p.task.defaultUnExport {
export = doNotExport
}
m := map[cc.StringID]*taggedStruct{}
var tags []cc.StringID
for _, v := range p.task.asts {
cc.Inspect(v.TranslationUnit, func(n cc.Node, entry bool) bool {
if entry {
switch x := n.(type) {
case *cc.Declarator:
if nm := x.Name().String(); strings.HasPrefix(nm, "_") {
break
}
p.captureStructTags(x, x.Type(), m, &tags)
case *cc.Declaration:
cc.Inspect(x.DeclarationSpecifiers, func(nn cc.Node, entry bool) bool {
switch y := nn.(type) {
case *cc.StructOrUnionSpecifier:
if tag := y.Token.Value; tag != 0 {
p.captureStructTags(y, y.Type(), m, &tags)
}
}
return true
})
}
}
return true
})
}
sort.Slice(tags, func(i, j int) bool { return tags[i].String() < tags[j].String() })
for _, k := range tags {
v := m[k]
//TODO rename conflicts
if v.conflicts {
delete(m, k)
continue
}
name := k.String()
switch export {
case doNotExport:
name = unCapitalize(name)
case doNotChange:
// nop
case exportCapitalize:
name = capitalize(name)
case exportPrefix:
name = p.task.exportStructs + name
}
v.name = p.scope.take(cc.String(name))
}
for _, k := range tags {
v := m[k]
if v != nil {
v.gotyp = p.structType(nil, v.ctyp)
}
}
p.structs = m
return nil
}
func (p *project) captureStructTags(n cc.Node, t cc.Type, m map[cc.StringID]*taggedStruct, tags *[]cc.StringID) {
if t == nil {
return
}
t = t.Alias()
for t.Kind() == cc.Ptr {
t = t.Alias().Elem().Alias()
}
if t.Kind() == cc.Invalid || t.IsIncomplete() {
return
}
switch t.Kind() {
case cc.Struct, cc.Union:
tag := t.Tag()
if tag == 0 {
return
}
ex := m[tag]
if ex != nil {
ts := p.typeSignature(n, t)
exs := p.typeSignature(n, ex.ctyp)
if ts != exs {
ex.conflicts = true
}
return
}
nf := t.NumField()
m[tag] = &taggedStruct{ctyp: t, node: n}
for idx := []int{0}; idx[0] < nf; idx[0]++ {
p.captureStructTags(n, t.FieldByIndex(idx).Type(), m, tags)
}
*tags = append(*tags, tag)
case cc.Array:
p.captureStructTags(n, t.Elem(), m, tags)
}
}
func (p *project) typeSignature(n cc.Node, t cc.Type) (r uint64) {
p.typeSigHash.Reset()
p.typeSignature2(n, &p.typeSigHash, t)
return p.typeSigHash.Sum64()
}
func (p *project) typeSignature2(n cc.Node, b *maphash.Hash, t cc.Type) {
t = t.Alias()
if t.IsIntegerType() {
if !t.IsSignedType() {
b.WriteByte('u')
}
fmt.Fprintf(b, "int%d", t.Size()*8)
return
}
if t.IsArithmeticType() {
b.WriteString(t.Kind().String())
return
}
structOrUnion := "struct"
switch t.Kind() {
case cc.Ptr:
fmt.Fprintf(b, "*%s", t.Elem())
case cc.Array:
if t.IsVLA() {
// trc("VLA")
p.err(n, "variable length arrays not supported: %v", t)
}
fmt.Fprintf(b, "[%d]%s", t.Len(), t.Elem())
case cc.Vector:
fmt.Fprintf(b, "[%d]%s", t.Len(), t.Elem())
case cc.Union:
structOrUnion = "union"
fallthrough
case cc.Struct:
b.WriteString(structOrUnion)
nf := t.NumField()
fmt.Fprintf(b, " %d{", nf)
b.WriteByte('{')
for idx := []int{0}; idx[0] < nf; idx[0]++ {
f := t.FieldByIndex(idx)
fmt.Fprintf(b, "%s:%d:%d:%v:%d:%d:",
f.Name(), f.BitFieldOffset(), f.BitFieldWidth(), f.IsBitField(), f.Offset(), f.Padding(),
)
p.typeSignature2(f.Declarator(), b, f.Type())
b.WriteByte(';')
}
b.WriteByte('}')
case cc.Void:
b.WriteString("void")
case cc.Invalid:
b.WriteString("invalid") //TODO fix cc/v3
default:
panic(todo("", p.pos(n), t, t.Kind()))
}
}
func (p *project) structType(n cc.Node, t cc.Type) string {
switch t.Kind() {
case cc.Struct, cc.Union:
tag := t.Tag()
if tag != 0 && p.structs != nil {
s := p.structs[tag]
if s == nil {
return p.structLiteral(n, t)
}
if s.gotyp == "" {
s.gotyp = p.structLiteral(n, t)
}
return s.gotyp
}
return p.structLiteral(n, t)
default:
panic(todo("internal error: %v", t.Kind()))
}
}
func (p *project) padName(n *int) string {
if !p.task.exportFieldsValid {
return "_"
}
*n++
return fmt.Sprintf("%s__ccgo_pad%d", p.task.exportFields, *n)
}
func (p *project) structLiteral(n cc.Node, t cc.Type) string {
var npad int
b := bytesBufferPool.Get().(*bytes.Buffer)
defer func() { b.Reset(); bytesBufferPool.Put(b) }()
switch t.Kind() {
case cc.Struct:
info := cc.NewStructLayout(t)
// trc("%v: %q\n%s", p.pos(n), t.Tag(), info)
b.WriteString("struct {")
if info.NeedExplicitAlign {
fmt.Fprintf(b, "%s [0]uint%d;", p.padName(&npad), 8*p.align(n, t))
}
var max uintptr
for _, off := range info.Offsets {
flds := info.OffsetToFields[off]
if off < max {
var a []string
var nmf cc.Field
for _, f := range flds {
if f.Name() != 0 && nmf == nil {
nmf = f
}
if !f.IsBitField() {
panic(todo("internal error %q, off %v max %v\n%s", f.Name(), off, max, info))
}
a = append(a, fmt.Sprintf("%s %s: %d", f.Type(), f.Name(), f.BitFieldWidth()))
}
fmt.Fprintf(b, "/* %s */", strings.Join(a, ", "))
continue
}
f := flds[0]
switch pad := info.PaddingsBefore[f]; {
case pad < 0:
continue
case pad > 0:
fmt.Fprintf(b, "%s [%d]byte;", p.padName(&npad), pad)
}
switch {
case f.IsBitField():
max += uintptr(f.BitFieldBlockWidth()) >> 3
var a []string
var nmf cc.Field
for _, f := range flds {
if f.Name() != 0 && nmf == nil {
nmf = f
}
if !f.IsBitField() {
panic(todo("internal error %q\n%s", f.Name(), info))
}
a = append(a, fmt.Sprintf("%s %s: %d", f.Type(), f.Name(), f.BitFieldWidth()))
}
if nmf == nil {
nmf = f
}
fmt.Fprintf(b, "%s uint%d /* %s */;", p.bitFieldName(n, nmf), f.BitFieldBlockWidth(), strings.Join(a, ", "))
default:
ft := f.Type()
if ft.Kind() == cc.Array && ft.IsIncomplete() || ft.Size() == 0 {
break
}
max += ft.Size()
fmt.Fprintf(b, "%s %s;", p.fieldName2(n, f), p.typ(n, ft))
}
}
if info.PaddingAfter != 0 {
fmt.Fprintf(b, "%s [%d]byte;", p.padName(&npad), info.PaddingAfter)
}
b.WriteByte('}')
case cc.Union:
b.WriteString("struct {")
info := cc.NewStructLayout(t)
if info.NeedExplicitAlign {
fmt.Fprintf(b, "%s [0]uint%d;", p.padName(&npad), 8*p.align(n, t))
}
al := uintptr(t.Align())
sz := t.Size()
if al > sz {
panic(todo("", p.pos(n)))
}
f := t.FieldByIndex([]int{0})
ft := f.Type()
al0 := ft.Align()
if f.IsBitField() {
al0 = f.BitFieldBlockWidth() >> 3
}
if al != uintptr(al0) {
fmt.Fprintf(b, "%s [0]uint%d;", p.padName(&npad), 8*al)
}
fsz := ft.Size()
switch {
case f.IsBitField():
fmt.Fprintf(b, "%s ", p.fieldName2(n, f))
fmt.Fprintf(b, "uint%d;", f.BitFieldBlockWidth())
fsz = uintptr(f.BitFieldBlockWidth()) >> 3
default:
fmt.Fprintf(b, "%s %s;", p.fieldName2(n, f), p.typ(n, ft))
}
if pad := sz - fsz; pad != 0 {
fmt.Fprintf(b, "%s [%d]byte;", p.padName(&npad), pad)
}
b.WriteByte('}')
default:
panic(todo("internal error: %v", t.Kind()))
}
r := b.String()
if p.task.verifyStructs {
if _, ok := p.verifyStructs[r]; !ok {
p.verifyStructs[r] = t
}
}
return r
}
func (p *project) align(nd cc.Node, t cc.Type) int {
switch n := t.Align(); {
case n <= 1:
return 1
case n <= 2:
return 2
case n <= 4:
return 4
case n <= 8:
return 8
default:
if !p.task.ignoreUnsupportedAligment {
p.err(nd, "unsupported alignment of type %s: %v", t, n)
}
return 8
}
}
func (p *project) bitFieldName(n cc.Node, f cc.Field) string {
if id := f.Name(); id != 0 {
return p.fieldName(n, id)
}
return fmt.Sprintf("__%d", f.Offset())
}
func (p *project) fieldName2(n cc.Node, f cc.Field) string {
if f.Name() != 0 {
return p.fieldName(n, f.Name())
}
return p.fieldName(n, cc.String(fmt.Sprintf("__%d", f.Offset())))
}
func (p *project) fieldName(n cc.Node, id cc.StringID) string {
if id == 0 {
panic(todo("", p.pos(n)))
}
if !p.task.exportFieldsValid {
s := id.String()
if p.task.defaultUnExport {
s = unCapitalize(s)
}
if !reservedNames[s] {
return s
}
return "__" + s
}
if s := p.task.exportFields; s != "" {
return s + id.String()
}
return capitalize(id.String())
}
func (p *project) dtyp(d *cc.Declarator) (r string) {
t := d.Type()
if t.IsIncomplete() {
if t.Kind() == cc.Array && d.IsParameter {
return "uintptr"
}
panic(todo(""))
}
return p.typ(d, t)
}
func (p *project) typ(nd cc.Node, t cc.Type) (r string) {
if t.IsIncomplete() {
panic(todo("", p.pos(nd), t))
}
if t.IsAliasType() && !t.IsScalarType() {
if tld := p.tlds[t.AliasDeclarator()]; tld != nil {
return tld.name
}
}
b := bytesBufferPool.Get().(*bytes.Buffer)
defer func() { b.Reset(); bytesBufferPool.Put(b) }()
if t.IsIntegerType() {
switch t.Kind() {
case cc.Int128:
fmt.Fprintf(b, "%sInt128", p.task.crt)
return b.String()
case cc.UInt128:
fmt.Fprintf(b, "%sUint128", p.task.crt)
return b.String()
}
if !t.IsSignedType() {
b.WriteByte('u')
}
if t.Size() > 8 {
p.err(nd, "unsupported C type: %v", t)
}
fmt.Fprintf(b, "int%d", 8*t.Size())
return b.String()
}
switch t.Kind() {
case cc.Ptr, cc.Function:
return "uintptr"
case cc.Double:
return "float64"
case cc.Float:
return "float32"
case cc.Array:
n := t.Len()
switch {
case t.IsVLA():
fmt.Fprintf(b, "uintptr")
default:
fmt.Fprintf(b, "[%d]%s", n, p.typ(nd, t.Elem()))
}
return b.String()
case cc.Vector:
n := t.Len()
fmt.Fprintf(b, "[%d]%s", n, p.typ(nd, t.Elem()))
return b.String()
case cc.Struct, cc.Union:
if tag := t.Tag(); tag != 0 {
if s := p.structs[tag]; s != nil {
if s.name == "" {
panic(todo("internal error %q", tag))
}
return s.name
}
}
return p.structType(nd, t)
}
panic(todo("", p.pos(nd), t.Kind(), t))
}
func isScalarKind(k cc.Kind) bool {
switch k {
case
cc.Char, cc.SChar, cc.UChar,
cc.Short, cc.UShort,
cc.Int, cc.UInt,
cc.Long, cc.ULong,
cc.LongLong, cc.ULongLong,
cc.Float, cc.Double,
cc.Ptr:
return true
}
return false
}
func (p *project) layoutTLDs() error {
var t0 time.Time
if p.task.traceTranslationUnits {
fmt.Printf("processing file scope declarations ... ")
t0 = time.Now()
defer func() { fmt.Println(time.Since(t0)) }()
}
exportExtern, exportTypedef := doNotChange, doNotChange
if p.task.exportExternsValid {
switch {
case p.task.exportExterns != "":
exportExtern = exportPrefix
default:
exportExtern = exportCapitalize
}
} else if p.task.defaultUnExport {
exportExtern = doNotExport
}
if p.task.exportTypedefsValid {
switch {
case p.task.exportTypedefs != "":
exportTypedef = exportPrefix
default:
exportTypedef = exportCapitalize
}
} else if p.task.defaultUnExport {
exportTypedef = doNotExport
}
var a []*cc.Declarator
if p.task.pkgName == "" || p.task.pkgName == "main" {
out:
for _, ast := range p.task.asts {
if a := ast.Scope[idMain]; len(a) != 0 {
switch x := a[0].(type) {
case *cc.Declarator:
if x.Linkage == cc.External {
p.isMain = true
p.scope.take(idMain)
break out
}
}
}
}
}
sharedFns := map[*cc.FunctionDefinition]struct{}{}
for _, ast := range p.task.asts {
a = a[:0]
for d := range ast.TLD {
if d.IsFunctionPrototype() {
continue
}
// https://gcc.gnu.org/onlinedocs/gcc/Inline.html
//
// If you specify both inline and extern in the function definition, then the
// definition is used only for inlining. In no case is the function compiled on
// its own, not even if you refer to its address explicitly. Such an address
// becomes an external reference, as if you had only declared the function, and
// had not defined it.
//
// This combination of inline and extern has almost the effect of a macro. The
// way to use it is to put a function definition in a header file with these
// keywords, and put another copy of the definition (lacking inline and extern)
// in a library file. The definition in the header file causes most calls to
// the function to be inlined. If any uses of the function remain, they refer
// to the single copy in the library.
if d.IsExtern() && d.Type().Inline() {
continue
}
if fn := d.FunctionDefinition(); fn != nil {
if _, ok := p.sharedFns[fn]; ok {
if _, ok := sharedFns[fn]; ok {
continue
}
sharedFns[fn] = struct{}{}
}
}
a = append(a, d)
p.wanted[d] = struct{}{}
}
sort.Slice(a, func(i, j int) bool {
return a[i].NameTok().Seq() < a[j].NameTok().Seq()
})
for _, d := range a {
switch d.Type().Kind() {
case cc.Struct, cc.Union:
p.checkAttributes(d.Type())
}
nm := d.Name()
name := nm.String()
switch d.Linkage {
case cc.External:
if ex := p.externs[nm]; ex != nil {
if _, ok := p.task.hide[name]; ok {
break
}
if d.Type().Kind() != cc.Function {
break
}
p.err(d, "redeclared: %s", d.Name())
break
}
isMain := p.isMain && nm == idMain
switch exportExtern {
case doNotExport:
name = unCapitalize(name)
case doNotChange:
// nop
case exportCapitalize:
name = capitalize(name)
case exportPrefix:
name = p.task.exportExterns + name
}
name = p.scope.take(cc.String(name))
if isMain {
p.mainName = name
d.Read++
}
tld := &tld{name: name}
p.externs[nm] = tld
for _, v := range ast.Scope[nm] {
if d, ok := v.(*cc.Declarator); ok {
p.tlds[d] = tld
}
}
if !isMain {
p.capi = append(p.capi, d.Name().String())
}
case cc.Internal:
if token.IsExported(name) && !p.isMain && p.task.exportExternsValid {
name = "s" + name
}
tld := &tld{name: p.scope.take(cc.String(name))}
for _, v := range ast.Scope[nm] {
if d, ok := v.(*cc.Declarator); ok {
p.tlds[d] = tld
}
}
case cc.None:
if d.IsTypedefName {
if d.Type().IsIncomplete() {
break
}
if exportTypedef == doNotChange && strings.HasPrefix(name, "__") {
break
}
ex, ok := p.typedefTypes[d.Name()]
if ok {
sig := p.typeSignature(d, d.Type())
if ex.sig == sig {
tld := ex.tld
for _, v := range ast.Scope[nm] {
if d, ok := v.(*cc.Declarator); ok {
p.tlds[d] = tld
}
}
break
}
}
switch exportTypedef {
case doNotExport:
name = unCapitalize(name)
case doNotChange:
// nop
case exportCapitalize:
name = capitalize(name)
case exportPrefix:
name = p.task.exportTypedefs + name
}
tld := &tld{name: p.scope.take(cc.String(name))}
p.typedefTypes[d.Name()] = &typedef{p.typeSignature(d, d.Type()), tld}
for _, v := range ast.Scope[nm] {
if d, ok := v.(*cc.Declarator); ok {
p.tlds[d] = tld
}
}
}
default:
panic(todo("", p.pos(d), nm, d.Linkage))
}
}
}
for _, ast := range p.task.asts {
for list := ast.TranslationUnit; list != nil; list = list.TranslationUnit {
decl := list.ExternalDeclaration
switch decl.Case {
case cc.ExternalDeclarationFuncDef: // FunctionDefinition
// ok
default:
continue
}
cc.Inspect(decl.FunctionDefinition.CompoundStatement, func(n cc.Node, entry bool) bool {
switch x := n.(type) {
case *cc.Declarator:
if x.IsFunctionPrototype() {
nm := x.Name()
if extern := p.externs[nm]; extern != nil {
break
}
tld := &tld{name: nm.String()}
for _, nd := range ast.Scope[nm] {
if d, ok := nd.(*cc.Declarator); ok {
p.tlds[d] = tld
}
}
}
}
return true
})
}
}
return nil
}
func (p *project) checkAttributes(t cc.Type) (r bool) {
r = true
for _, v := range t.Attributes() {
cc.Inspect(v, func(n cc.Node, entry bool) bool {
if !entry {
return true
}
switch x := n.(type) {
case *cc.AttributeValue:
if x.Token.Value != idAligned {
break
}
//TODO switch v := x.ExpressionList.AssignmentExpression.Operand.Value().(type) {
//TODO default:
//TODO panic(todo("%T(%v)", v, v))
//TODO }
}
return true
})
}
switch t.Kind() {
case cc.Struct, cc.Union:
for i := []int{0}; i[0] < t.NumField(); i[0]++ {
f := t.FieldByIndex(i)
if !p.checkAttributes(f.Type()) {
return false
}
sd := f.Declarator()
if sd == nil {
continue
}
cc.Inspect(sd.StructDeclaration().SpecifierQualifierList, func(n cc.Node, entry bool) bool {
if !entry {
return true
}
switch x := n.(type) {
case *cc.AttributeValue:
if x.Token.Value == idPacked {
p.err(sd, "unsupported attribute: packed")
r = false
return false
}
if x.Token.Value != idAligned {
break
}
switch v := x.ExpressionList.AssignmentExpression.Operand.Value().(type) {
case cc.Int64Value:
if int(v) != t.Align() {
p.err(sd, "unsupported attribute: alignment")
r = false
return false
}
default:
panic(todo("%T(%v)", v, v))
}
}
return true
})
if !r {
return false
}
}
}
return r
}
func unCapitalize(s string) string {
if strings.HasPrefix(s, "_") {
return s
}
a := []rune(s)
return strings.ToLower(string(a[0])) + string(a[1:])
}
func capitalize(s string) string {
if strings.HasPrefix(s, "_") {
s = "X" + s
}
a := []rune(s)
return strings.ToUpper(string(a[0])) + string(a[1:])
}
func (p *project) main() error {
targs := append([]string(nil), p.task.args...)
for i, v := range targs {
if v == "" {
targs[i] = `""`
}
}
p.o(`// Code generated by '%s %s', DO NOT EDIT.
package %s
`,
filepath.Base(p.task.args[0]),
strings.Join(targs[1:], " "),
p.task.pkgName,
)
if len(p.defineLines) != 0 {
p.w("\nconst (")
p.w("%s", strings.Join(p.defineLines, "\n"))
p.w("\n)\n\n")
}
var a []*enumSpec
for _, es := range p.enumSpecs {
if es.spec.LexicalScope().Parent() == nil && !es.emitted {
a = append(a, es)
}
}
sort.Slice(a, func(i, j int) bool {
return a[i].decl.Position().String() < a[j].decl.Position().String()
})
for _, es := range a {
es.emit(p)
}
for i, v := range p.task.asts {
var t0 time.Time
if p.task.traceTranslationUnits {
fmt.Printf("Go back end %v/%v: %s ... ", i+1, len(p.task.asts), filepath.Base(p.task.sources[i].Name))
t0 = time.Now()
}
p.oneAST(v)
if p.task.traceTranslationUnits {
fmt.Println(time.Since(t0))
}
p.task.asts[i] = nil
memGuard(i, p.task.isScripted)
}
sort.Slice(p.task.imported, func(i, j int) bool { return p.task.imported[i].path < p.task.imported[j].path })
p.o(`import (
"math"
"reflect"
"sync/atomic"
"unsafe"
`)
if len(p.verifyStructs) != 0 {
p.o("\t\"fmt\"\n")
}
first := true
libc := false
for _, v := range p.task.imported {
if v.used {
if v.path == p.task.crtImportPath {
libc = true
}
if first {
p.o("\n")
first = false
}
p.o("\t%q\n", v.path)
}
}
if p.task.crtImportPath != "" {
if !libc {
p.o("\t%q\n", p.task.crtImportPath)
}
p.o("\t%q\n", p.task.crtImportPath+"/sys/types")
}
p.o(`)
var _ = math.Pi
var _ reflect.Kind
var _ atomic.Value
var _ unsafe.Pointer
`)
if p.task.crtImportPath != "" {
if libc {
p.o("var _ *libc.TLS\n")
}
p.o("var _ types.Size_t\n")
}
if p.isMain {
p.o(`
func main() { %sStart(%s) }`, p.task.crt, p.mainName)
}
p.flushStructs()
p.initPatches()
p.flushTS()
if !p.task.noCapi {
p.flushCAPI()
}
p.doVerifyStructs()
if err := p.Err(); err != nil {
return err
}
if _, err := p.buf.WriteTo(p.task.out); err != nil {
return err
}
return p.Err()
}
func (p *project) doVerifyStructs() {
if len(p.verifyStructs) == 0 {
return
}
var a []string
for k := range p.verifyStructs {
a = append(a, k)
}
sort.Strings(a)
p.w("\n\nfunc init() {")
n := 0
for _, k := range a {
t := p.verifyStructs[k]
p.w("\nvar v%d %s", n, k)
p.w("\nif g, e := unsafe.Sizeof(v%d), uintptr(%d); g != e { panic(fmt.Sprintf(`invalid struct/union size, got %%v, expected %%v`, g, e))}", n, t.Size())
nf := t.NumField()
for idx := []int{0}; idx[0] < nf; idx[0]++ {
f := t.FieldByIndex(idx)
if f.IsFlexible() {
break
}
if f.IsBitField() || f.Type().Size() == 0 {
continue
}
nm := p.fieldName2(f.Declarator(), f)
switch {
case t.Kind() == cc.Union:
if f.Offset() != 0 {
panic(todo(""))
}
if idx[0] != 0 {
break
}
fallthrough
default:
p.w("\nif g, e := unsafe.Offsetof(v%d.%s), uintptr(%d); g != e { panic(fmt.Sprintf(`invalid struct/union field offset, got %%v, expected %%v`, g, e))}", n, nm, f.Offset())
p.w("\nif g, e := unsafe.Sizeof(v%d.%s), uintptr(%d); g != e { panic(fmt.Sprintf(`invalid struct/union field size, got %%v, expected %%v`, g, e))}", n, nm, f.Type().Size())
}
}
n++
}
p.w("\n}\n")
}
func (p *project) flushCAPI() {
if p.isMain {
return
}
b := bytes.NewBuffer(nil)
fmt.Fprintf(b, `// Code generated by '%s %s', DO NOT EDIT.
package %s
`,
filepath.Base(p.task.args[0]),
strings.Join(p.task.args[1:], " "),
p.task.pkgName,
)
fmt.Fprintf(b, "\n\nvar CAPI = map[string]struct{}{")
sort.Strings(p.capi)
for _, nm := range p.capi {
fmt.Fprintf(b, "\n%q: {},", nm)
}
fmt.Fprintf(b, "\n}\n")
if err := ioutil.WriteFile(p.task.capif, b.Bytes(), 0644); err != nil {
p.err(nil, "%v", err)
return
}
if out, err := exec.Command("gofmt", "-r", "(x) -> x", "-l", "-s", "-w", p.task.capif).CombinedOutput(); err != nil {
p.err(nil, "%s: %v", out, err)
}
if out, err := exec.Command("gofmt", "-l", "-s", "-w", p.task.capif).CombinedOutput(); err != nil {
p.err(nil, "%s: %v", out, err)
}
}
func (p *project) initPatches() {
var tlds []*tld
for _, tld := range p.tlds {
if len(tld.patches) != 0 {
tlds = append(tlds, tld)
}
}
if len(tlds) == 0 {
return
}
sort.Slice(tlds, func(i, j int) bool { return tlds[i].name < tlds[j].name })
p.w("\n\nfunc init() {")
for _, tld := range tlds {
for _, patch := range tld.patches {
var fld string
if patch.fld != nil {
fld = fmt.Sprintf("/* .%s */", patch.fld.Name())
}
init := patch.init
expr := init.AssignmentExpression
d := expr.Declarator()
switch {
case d != nil && d.Type().Kind() == cc.Function:
p.w("\n*(*")
p.functionSignature(d, nil, d.Type(), "")
p.w(")(unsafe.Pointer(uintptr(unsafe.Pointer(&%s))+%d%s)) = ", tld.name, init.Offset, fld)
p.declarator(init, nil, d, d.Type(), exprFunc, 0)
default:
p.w("\n*(*%s)(unsafe.Pointer(uintptr(unsafe.Pointer(&%s))+%d%s)) = ", p.typ(init, patch.t), tld.name, init.Offset, fld)
p.assignmentExpression(nil, expr, patch.t, exprValue, 0)
}
p.w("// %s:", p.pos(init))
}
}
p.w("\n}\n")
}
func (p *project) Err() error {
if len(p.errors) == 0 {
return nil
}
var lpos token.Position
w := 0
for _, v := range p.errors {
if lpos.Filename != "" {
if v.Pos.Filename == lpos.Filename && v.Pos.Line == lpos.Line && !strings.HasPrefix(v.Msg, tooManyErrors) {
continue
}
}
p.errors[w] = v
w++
lpos = v.Pos
}
p.errors = p.errors[:w]
sort.Slice(p.errors, func(i, j int) bool {
a := p.errors[i]
if a.Msg == tooManyErrors {
return false
}
b := p.errors[j]
if b.Msg == tooManyErrors {
return true
}
if !a.Pos.IsValid() && b.Pos.IsValid() {
return true
}
if a.Pos.IsValid() && !b.Pos.IsValid() {
return false
}
if a.Pos.Filename < b.Pos.Filename {
return true
}
if a.Pos.Filename > b.Pos.Filename {
return false
}
if a.Pos.Line < b.Pos.Line {
return true
}
if a.Pos.Line > b.Pos.Line {
return false
}
return a.Pos.Column < b.Pos.Column
})
a := make([]string, 0, len(p.errors))
for _, v := range p.errors {
a = append(a, v.Error())
}
return fmt.Errorf("%s", strings.Join(a, "\n"))
}
func (p *project) flushTS() {
b := p.ts.Bytes()
if len(b) != 0 {
p.w("\n\n")
//TODO add cmd line option for this
//TODO s := strings.TrimSpace(hex.Dump(b))
//TODO a := strings.Split(s, "\n")
//TODO p.w("// %s\n", strings.Join(a, "\n// "))
p.w("var %s = %q\n", p.tsName, b)
p.w("var %s = (*reflect.StringHeader)(unsafe.Pointer(&%s)).Data\n", p.tsNameP, p.tsName)
}
if len(p.tsW) != 0 {
p.w("var %s = [...]%s{", p.tsWName, p.typ(nil, p.ast.WideCharType))
for _, v := range p.tsW {
p.w("%d, ", v)
}
p.w("}\n")
p.w("var %s = uintptr(unsafe.Pointer(&%s[0]))\n", p.tsWNameP, p.tsWName)
}
}
func (p *project) flushStructs() {
var a []*taggedStruct
for _, v := range p.structs {
if !v.emitted {
a = append(a, v)
}
}
sort.Slice(a, func(i, j int) bool { return a[i].name < a[j].name })
for _, v := range a {
v.emit(p, nil)
}
}
func (p *project) oneAST(ast *cc.AST) {
p.ast = ast
for list := ast.TranslationUnit; list != nil; list = list.TranslationUnit {
p.externalDeclaration(list.ExternalDeclaration)
}
p.w("%s", tidyCommentString(ast.TrailingSeperator.String()))
}
func (p *project) externalDeclaration(n *cc.ExternalDeclaration) {
switch n.Case {
case cc.ExternalDeclarationFuncDef: // FunctionDefinition
p.functionDefinition(n.FunctionDefinition)
case cc.ExternalDeclarationDecl: // Declaration
p.declaration(nil, n.Declaration, false)
case cc.ExternalDeclarationAsm: // AsmFunctionDefinition
// nop
case cc.ExternalDeclarationAsmStmt: // AsmStatement
panic(todo("", p.pos(n)))
case cc.ExternalDeclarationEmpty: // ';'
// nop
case cc.ExternalDeclarationPragma: // PragmaSTDC
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) declaration(f *function, n *cc.Declaration, topDecl bool) {
cc.Inspect(n.DeclarationSpecifiers, func(m cc.Node, entry bool) bool {
switch x := m.(type) {
case *cc.EnumSpecifier:
if f == nil {
p.enumSpecs[x].emit(p)
}
case *cc.StructOrUnionSpecifier:
if tag := x.Token.Value; tag != 0 {
switch {
case f == nil:
p.structs[tag].emit(p, n.DeclarationSpecifiers)
default:
p.localTaggedStructs = append(p.localTaggedStructs, func() {
p.structs[tag].emit(p, n.DeclarationSpecifiers)
})
}
}
}
return true
})
if n.InitDeclaratorList == nil {
return
}
// DeclarationSpecifiers InitDeclaratorList ';'
sep := tidyComment("\n", n) //TODO repeats
for list := n.InitDeclaratorList; list != nil; list = list.InitDeclaratorList {
p.initDeclarator(f, list.InitDeclarator, sep, topDecl)
sep = "\n"
}
}
func (p *project) initDeclarator(f *function, n *cc.InitDeclarator, sep string, topDecl bool) {
if f == nil {
p.tld(f, n, sep, false)
return
}
d := n.Declarator
if d.IsExtern() || d.IsTypedefName {
return
}
if tld := p.tlds[d]; tld != nil && !topDecl { // static local
if !p.pass1 {
p.staticQueue = append(p.staticQueue, n)
}
return
}
local := f.locals[d]
if local == nil { // Dead declaration.
return
}
block := f.block
t := d.Type()
vla := t.Kind() == cc.Array && t.IsVLA()
if vla && p.pass1 {
f.vlas[d] = struct{}{}
return
}
switch n.Case {
case cc.InitDeclaratorDecl: // Declarator AttributeSpecifierList
if block.noDecl || block.topDecl && !topDecl {
return
}
switch {
case vla:
p.initDeclaratorDeclVLA(f, n, sep)
default:
p.initDeclaratorDecl(f, n, sep)
}
case cc.InitDeclaratorInit: // Declarator AttributeSpecifierList '=' Initializer
if vla {
panic(todo(""))
}
if f.block.topDecl {
switch {
case topDecl:
p.initDeclaratorDecl(f, n, sep)
if local.forceRead && !local.isPinned {
p.w("_ = %s;", local.name)
}
default:
sv := f.condInitPrefix
f.condInitPrefix = func() {
p.declarator(d, f, d, d.Type(), exprLValue, 0)
p.w(" = ")
}
switch {
case p.isConditionalInitializer(n.Initializer):
p.assignmentExpression(f, n.Initializer.AssignmentExpression, d.Type(), exprCondInit, 0)
default:
f.condInitPrefix()
p.initializer(f, n.Initializer, d.Type(), d.StorageClass, nil)
}
f.condInitPrefix = sv
p.w(";")
}
return
}
p.w("%s", sep)
switch {
case local.isPinned:
sv := f.condInitPrefix
f.condInitPrefix = func() {
//TODO- p.declarator(d, f, d, d.Type(), exprLValue, 0)
//TODO- p.w(" = ")
p.w("*(*%s)(unsafe.Pointer(%s%s/* %s */)) = ", p.typ(n, d.Type()), f.bpName, nonZeroUintptr(local.off), local.name)
}
switch {
case p.isConditionalInitializer(n.Initializer):
p.assignmentExpression(f, n.Initializer.AssignmentExpression, d.Type(), exprCondInit, 0)
default:
f.condInitPrefix()
p.initializer(f, n.Initializer, d.Type(), d.StorageClass, nil)
p.w(";")
}
f.condInitPrefix = sv
p.w(";")
default:
var semi string
switch {
case block.noDecl:
semi = ""
default:
p.w("var %s ", local.name)
if !isAggregateTypeOrUnion(d.Type()) {
p.w("%s ", p.typ(n, d.Type()))
}
semi = ";"
}
switch {
case p.isConditionalInitializer(n.Initializer):
p.w("%s", semi)
sv := f.condInitPrefix
f.condInitPrefix = func() { p.w("%s = ", local.name) }
p.assignmentExpression(f, n.Initializer.AssignmentExpression, d.Type(), exprCondInit, 0)
f.condInitPrefix = sv
default:
if block.noDecl {
p.w("%s", local.name)
}
p.w(" = ")
p.initializer(f, n.Initializer, d.Type(), d.StorageClass, nil)
}
p.w(";")
}
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
if !block.noDecl && local.forceRead && !local.isPinned {
p.w("_ = %s;", local.name)
}
}
func (p *project) isConditionalInitializer(n *cc.Initializer) bool {
return n.Case == cc.InitializerExpr && p.isConditionalAssignmentExpr(n.AssignmentExpression)
}
func (p *project) isConditionalAssignmentExpr(n *cc.AssignmentExpression) bool {
return n.Case == cc.AssignmentExpressionCond &&
n.ConditionalExpression.Case == cc.ConditionalExpressionCond
}
func (p *project) initDeclaratorDeclVLA(f *function, n *cc.InitDeclarator, sep string) {
d := n.Declarator
local := f.locals[d]
if strings.TrimSpace(sep) == "" {
sep = "\n"
}
if local.isPinned {
panic(todo(""))
p.w("%s// var %s %s at %s%s, %d\n", sep, local.name, p.typ(n, d.Type()), f.bpName, nonZeroUintptr(local.off), d.Type().Size())
return
}
p.w("%s%s = %sXrealloc(%s, %s, types.Size_t(", sep, local.name, p.task.crt, f.tlsName, local.name)
e := d.Type().LenExpr()
p.assignmentExpression(f, e, e.Operand.Type(), exprValue, 0)
if sz := d.Type().Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
p.w("));")
}
func (p *project) initDeclaratorDecl(f *function, n *cc.InitDeclarator, sep string) {
d := n.Declarator
local := f.locals[d]
if strings.TrimSpace(sep) == "" {
sep = "\n"
}
if local.isPinned {
p.w("%s// var %s %s at %s%s, %d\n", sep, local.name, p.typ(n, d.Type()), f.bpName, nonZeroUintptr(local.off), d.Type().Size())
return
}
p.w("%svar %s %s;", sep, local.name, p.typ(n, d.Type()))
}
func (p *project) declarator(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprLValue:
p.declaratorLValue(n, f, d, t, mode, flags)
case exprFunc:
p.declaratorFunc(n, f, d, t, mode, flags)
case exprValue:
p.declaratorValue(n, f, d, t, mode, flags)
case exprAddrOf:
p.declaratorAddrOf(n, f, d, t, flags)
case exprSelect:
p.declaratorSelect(n, f, d)
case exprDecay:
p.declaratorDecay(n, f, d, t, mode, flags)
default:
panic(todo("", mode))
}
}
func (p *project) declaratorDecay(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
if d.Type().Kind() != cc.Array {
panic(todo("", n.Position(), p.pos(d)))
}
if f != nil {
if local := f.locals[d]; local != nil {
if d.Type().IsVLA() {
switch {
case local.isPinned:
panic(todo(""))
default:
p.w("%s", local.name)
return
}
}
if d.IsParameter {
p.w("%s", local.name)
return
}
if p.pass1 {
if !d.Type().IsVLA() {
f.pin(n, d)
}
return
}
if !local.isPinned {
p.err(n, "%v: %v: missed pinning", n.Position(), d.Position(), d.Name())
}
p.w("(%s%s)/* &%s[0] */", f.bpName, nonZeroUintptr(local.off), local.name)
return
}
}
if x := p.tlds[d]; x != nil && d.IsStatic() {
p.w("uintptr(unsafe.Pointer(&%s))", x.name)
return
}
switch x := p.symtab[d.Name().String()].(type) {
case *tld:
p.w("uintptr(unsafe.Pointer(&%s))", x.name)
case *imported:
x.used = true
p.w("uintptr(unsafe.Pointer(&%sX%s))", x.qualifier, d.Name())
default:
panic(todo("%v: %v: %q %T", n.Position(), p.pos(d), d.Name(), x))
}
}
func (p *project) declaratorValue(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
switch k := p.declaratorKind(d); k {
case opNormal:
p.declaratorValueNormal(n, f, d, t, mode, flags)
case opArray:
p.declaratorValueArray(n, f, d, t, mode, flags)
case opFunction:
p.declarator(n, f, d, t, exprAddrOf, flags)
case opUnion:
p.declaratorValueUnion(n, f, d, t, mode, flags)
case opArrayParameter:
p.declaratorValueArrayParameter(n, f, d, t, mode, flags)
default:
panic(todo("", d.Position(), k))
}
}
func (p *project) declaratorValueArrayParameter(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
if d.Type().IsScalarType() {
defer p.w("%s", p.convertType(n, d.Type(), t, flags))
}
local := f.locals[d]
if local.isPinned {
p.w("*(*%s)(unsafe.Pointer(%s%s/* %s */))", p.typ(n, paramTypeDecay(d)), f.bpName, nonZeroUintptr(local.off), local.name)
return
}
p.w("%s", local.name)
}
func (p *project) declaratorValueUnion(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
if d.Type().IsScalarType() {
defer p.w("%s", p.convertType(n, d.Type(), t, flags))
}
if f != nil {
if local := f.locals[d]; local != nil {
if local.isPinned {
p.w("*(*%s)(unsafe.Pointer(%s%s/* %s */))", p.typ(d, d.Type()), f.bpName, nonZeroUintptr(local.off), local.name)
return
}
p.w("%s", local.name)
return
}
}
p.declaratorDefault(n, d)
}
func (p *project) isVolatileOrAtomic(d *cc.Declarator) bool {
if d.Type().IsVolatile() || d.Type().IsAtomic() {
return true
}
_, ok := p.task.volatiles[d.Name()]
return ok
}
func (p *project) declaratorDefault(n cc.Node, d *cc.Declarator) {
if x := p.tlds[d]; x != nil && d.IsStatic() {
if p.isVolatileOrAtomic(d) {
p.atomicLoadNamedAddr(n, d.Type(), x.name)
return
}
p.w("%s", x.name)
return
}
switch x := p.symtab[d.Name().String()].(type) {
case *tld:
if p.isVolatileOrAtomic(d) {
p.atomicLoadNamedAddr(n, d.Type(), x.name)
return
}
p.w("%s", x.name)
case *imported:
x.used = true
if p.isVolatileOrAtomic(d) {
p.atomicLoadNamedAddr(n, d.Type(), fmt.Sprintf("%sX%s", x.qualifier, d.Name()))
return
}
p.w("%sX%s", x.qualifier, d.Name())
default:
if d.IsExtern() {
switch d.Name() {
case idEnviron:
if d.Type().String() == "pointer to pointer to char" {
p.w("%sEnviron()", p.task.crt)
return
}
}
}
if d.Linkage == cc.External && p.task.nostdlib {
p.w("X%s", d.Name())
return
}
id := fmt.Sprintf("__builtin_%s", d.Name())
switch x := p.symtab[id].(type) {
case *imported:
x.used = true
p.w("%sX%s", x.qualifier, d.Name())
return
}
if !d.IsImplicit() {
nm := d.Name()
name := nm.String()
switch d.Linkage {
case cc.External:
name = p.task.exportExterns + name
tld := &tld{name: name}
p.externs[nm] = tld
p.w("%s", name)
return
case cc.Internal:
if token.IsExported(name) {
name = "s" + name
}
tld := &tld{name: p.scope.take(cc.String(name))}
for _, v := range p.ast.Scope[nm] {
if d, ok := v.(*cc.Declarator); ok {
p.tlds[d] = tld
}
}
p.w("%s", name)
return
}
}
p.err(n, "back-end: undefined: %s", d.Name())
}
}
func (p *project) declaratorValueArray(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
if t.IsIntegerType() {
defer p.w("%s", p.convertType(n, nil, t, flags))
}
if f != nil {
if local := f.locals[d]; local != nil {
if local.isPinned {
p.w("(%s%s)/* %s */", f.bpName, nonZeroUintptr(local.off), local.name)
return
}
p.w("%s", local.name)
return
}
}
p.declaratorDefault(n, d)
}
func (p *project) declaratorValueNormal(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
if d.Type().IsScalarType() {
defer p.w("%s", p.convertType(n, d.Type(), t, flags))
}
if f != nil {
if local := f.locals[d]; local != nil {
if local.isPinned {
if p.isVolatileOrAtomic(d) && d.IsParameter && d.Write != 0 {
p.w("%sAtomicLoadP%s(%s%s/* %s */)", p.task.crt, p.helperType(n, d.Type()), f.bpName, nonZeroUintptr(local.off), local.name)
return
}
p.w("*(*%s)(unsafe.Pointer(%s%s/* %s */))", p.typ(d, d.Type()), f.bpName, nonZeroUintptr(local.off), local.name)
return
}
if p.isVolatileOrAtomic(d) && d.IsParameter && d.Write != 0 {
p.atomicLoadNamedAddr(n, d.Type(), local.name)
return
}
p.w("%s", local.name)
return
}
}
p.declaratorDefault(n, d)
}
func (p *project) declaratorFunc(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
switch k := p.declaratorKind(d); k {
case opFunction:
p.declaratorFuncFunc(n, f, d, t, exprValue, flags)
case opNormal:
p.declaratorFuncNormal(n, f, d, t, exprValue, flags)
default:
panic(todo("", d.Position(), k))
}
}
func (p *project) declaratorFuncNormal(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
u := d.Type()
if u.Kind() == cc.Ptr {
u = u.Elem()
}
switch u.Kind() {
case cc.Function:
if local := f.locals[d]; local != nil {
if local.isPinned {
p.w("(*(*")
p.functionSignature(n, f, u, "")
p.w(")(unsafe.Pointer(%s%s)))", f.bpName, nonZeroUintptr(local.off))
return
}
if d.IsParameter {
p.w("(*(*")
p.functionSignature(n, f, u, "")
p.w(")(unsafe.Pointer(&%s)))", local.name)
return
}
panic(todo("", p.pos(d)))
}
if x := p.tlds[d]; x != nil && d.IsStatic() {
p.w("(*(*")
p.functionSignature(n, f, u, "")
p.w(")(unsafe.Pointer(&%s)))", x.name)
return
}
switch x := p.symtab[d.Name().String()].(type) {
case *tld:
p.w("(*(*")
p.functionSignature(n, f, u, "")
p.w(")(unsafe.Pointer(&%s)))", x.name)
case *imported:
x.used = true
p.w("uintptr(unsafe.Pointer(&%sX%s))", x.qualifier, d.Name())
default:
panic(todo("%v: %v: %q", n.Position(), p.pos(d), d.Name()))
}
default:
panic(todo("", p.pos(d), u))
}
}
func (p *project) declaratorFuncFunc(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
switch d.Type().Kind() {
case cc.Function:
// ok
default:
panic(todo("", p.pos(d), d.Type(), d.Type().Kind()))
}
if f != nil {
if local := f.locals[d]; local != nil {
if local.isPinned {
panic(todo(""))
}
p.w(" %s", local.name)
return
}
}
p.declaratorDefault(n, d)
}
func (p *project) declaratorLValue(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
switch k := p.declaratorKind(d); k {
case opNormal, opArrayParameter, opUnion:
p.declaratorLValueNormal(n, f, d, t, mode, flags)
case opArray:
p.declaratorLValueArray(n, f, d, t, mode, flags)
default:
panic(todo("", d.Position(), k))
}
}
func (p *project) declaratorLValueArray(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
if f != nil {
if local := f.locals[d]; local != nil {
if local.isPinned {
p.w("*(*%s)(unsafe.Pointer(%s%s/* %s */))", p.typ(d, d.Type()), f.bpName, nonZeroUintptr(local.off), local.name)
return
}
p.w("%s", local.name)
return
}
}
p.declaratorDefault(n, d)
}
func (p *project) declaratorLValueNormal(n cc.Node, f *function, d *cc.Declarator, t cc.Type, mode exprMode, flags flags) {
if p.isVolatileOrAtomic(d) && flags&fVolatileOk == 0 {
panic(todo("", n.Position(), d.Position()))
}
if d.Type().IsScalarType() {
defer p.w("%s", p.convertType(n, d.Type(), t, flags))
}
if f != nil {
if local := f.locals[d]; local != nil {
if local.isPinned {
p.w("*(*%s)(unsafe.Pointer(%s%s/* %s */))", p.dtyp(d), f.bpName, nonZeroUintptr(local.off), local.name)
return
}
p.w("%s", local.name)
return
}
}
p.declaratorLValueDefault(n, d)
}
func (p *project) declaratorLValueDefault(n cc.Node, d *cc.Declarator) {
if x := p.tlds[d]; x != nil && d.IsStatic() {
p.w("%s", x.name)
return
}
switch x := p.symtab[d.Name().String()].(type) {
case *tld:
p.w("%s", x.name)
case *imported:
x.used = true
p.w("%sX%s", x.qualifier, d.Name())
default:
if d.IsExtern() {
switch d.Name() {
case idEnviron:
if d.Type().String() == "pointer to pointer to char" {
p.w("*(*uintptr)(unsafe.Pointer(%sEnvironP()))", p.task.crt)
return
}
}
}
panic(todo("%v: %v: %q", n.Position(), p.pos(d), d.Name()))
}
}
func (p *project) declaratorKind(d *cc.Declarator) opKind {
switch {
case p.isArrayParameterDeclarator(d):
return opArrayParameter
case !p.pass1 && p.isArrayDeclarator(d):
return opArray
case d.Type().Kind() == cc.Function && !d.IsParameter:
return opFunction
case d.Type().Kind() == cc.Union:
return opUnion
default:
return opNormal
}
}
func (p *project) declaratorSelect(n cc.Node, f *function, d *cc.Declarator) {
switch k := p.declaratorKind(d); k {
case opNormal:
p.declaratorSelectNormal(n, f, d)
case opArray:
p.declaratorSelectArray(n, f, d)
default:
panic(todo("", d.Position(), k))
}
}
func (p *project) declaratorSelectArray(n cc.Node, f *function, d *cc.Declarator) {
if local := f.locals[d]; local != nil {
if local.isPinned {
panic(todo("", p.pos(n)))
//TODO type error
p.w("(*%s)(unsafe.Pointer(%s%s/* &%s */))", p.typ(d, d.Type()), f.bpName, nonZeroUintptr(local.off), local.name)
return
}
p.w("%s", local.name)
return
}
p.declaratorDefault(n, d)
}
func (p *project) declaratorSelectNormal(n cc.Node, f *function, d *cc.Declarator) {
if local := f.locals[d]; local != nil {
if local.isPinned {
p.w("(*%s)(unsafe.Pointer(%s%s/* &%s */))", p.typ(d, d.Type()), f.bpName, nonZeroUintptr(local.off), local.name)
return
}
p.w("%s", local.name)
return
}
p.declaratorDefault(n, d)
}
func (p *project) declaratorAddrOf(n cc.Node, f *function, d *cc.Declarator, t cc.Type, flags flags) {
switch k := p.declaratorKind(d); k {
case opArray:
p.declaratorAddrOfArray(n, f, d)
case opNormal:
p.declaratorAddrOfNormal(n, f, d, flags)
case opUnion:
p.declaratorAddrOfUnion(n, f, d)
case opFunction:
p.declaratorAddrOfFunction(n, f, d)
case opArrayParameter:
p.declaratorAddrOfArrayParameter(n, f, d)
default:
panic(todo("", d.Position(), k))
}
}
func (p *project) declaratorAddrOfArrayParameter(n cc.Node, f *function, d *cc.Declarator) {
if p.pass1 {
f.pin(n, d)
return
}
local := f.locals[d]
p.w("(%s%s)/* &%s */", f.bpName, nonZeroUintptr(local.off), local.name)
}
func (p *project) declaratorAddrOfFunction(n cc.Node, f *function, d *cc.Declarator) {
if d.Type().Kind() != cc.Function {
panic(todo("", p.pos(n)))
}
if x := p.tlds[d]; x != nil && d.IsStatic() {
p.w("*(*uintptr)(unsafe.Pointer(&struct{f ")
p.functionSignature(n, f, d.Type(), "")
p.w("}{%s}))", x.name)
return
}
switch x := p.symtab[d.Name().String()].(type) {
case *tld:
p.w("*(*uintptr)(unsafe.Pointer(&struct{f ")
p.functionSignature(n, f, d.Type(), "")
p.w("}{%s}))", x.name)
case *imported:
x.used = true
p.w("*(*uintptr)(unsafe.Pointer(&struct{f ")
p.functionSignature(n, f, d.Type(), "")
p.w("}{%sX%s}))", x.qualifier, d.Name())
default:
p.err(d, "back-end: undefined: %s", d.Name())
}
}
func (p *project) declaratorAddrOfUnion(n cc.Node, f *function, d *cc.Declarator) {
if f != nil {
if local := f.locals[d]; local != nil {
if p.pass1 {
f.pin(n, d)
return
}
if local.isPinned {
p.w("(%s%s)/* &%s */", f.bpName, nonZeroUintptr(local.off), local.name)
return
}
panic(todo("", p.pos(n)))
}
}
if x := p.tlds[d]; x != nil && d.IsStatic() {
p.w("uintptr(unsafe.Pointer(&%s))", x.name)
return
}
switch x := p.symtab[d.Name().String()].(type) {
case *tld:
p.w("uintptr(unsafe.Pointer(&%s))", x.name)
case *imported:
x.used = true
p.w("uintptr(unsafe.Pointer(&%sX%s))", x.qualifier, d.Name())
default:
panic(todo("%v: %v: %q", n.Position(), p.pos(d), d.Name()))
}
}
func (p *project) declaratorAddrOfNormal(n cc.Node, f *function, d *cc.Declarator, flags flags) {
if f != nil {
if local := f.locals[d]; local != nil {
if p.pass1 && flags&fAddrOfFuncPtrOk == 0 {
f.pin(n, d)
return
}
if local.isPinned {
p.w("(%s%s)/* &%s */", f.bpName, nonZeroUintptr(local.off), local.name)
return
}
if flags&fAddrOfFuncPtrOk != 0 {
if dt := d.Type(); dt.Kind() == cc.Ptr {
if elem := dt.Elem(); elem.Kind() == cc.Function || elem.Kind() == cc.Ptr && elem.Elem().Kind() == cc.Function {
p.w("&%s", local.name)
return
}
}
}
panic(todo("", p.pos(n), p.pos(d), d.Name(), d.Type(), d.IsParameter, d.AddressTaken, flags&fAddrOfFuncPtrOk != 0))
}
}
if x := p.tlds[d]; x != nil && d.IsStatic() {
p.w("uintptr(unsafe.Pointer(&%s))", x.name)
return
}
switch x := p.symtab[d.Name().String()].(type) {
case *tld:
p.w("uintptr(unsafe.Pointer(&%s))", x.name)
case *imported:
x.used = true
p.w("uintptr(unsafe.Pointer(&%sX%s))", x.qualifier, d.Name())
default:
p.err(n, "undefined: %s", d.Name())
}
}
func (p *project) declaratorAddrOfArray(n cc.Node, f *function, d *cc.Declarator) {
if f != nil {
if local := f.locals[d]; local != nil {
if p.pass1 {
f.pin(n, d)
return
}
if local.isPinned {
p.w("(%s%s)/* &%s */", f.bpName, nonZeroUintptr(local.off), local.name)
return
}
panic(todo("", p.pos(d), d.Name(), d.Type(), d.IsParameter))
}
}
if x := p.tlds[d]; x != nil && d.IsStatic() {
p.w("uintptr(unsafe.Pointer(&%s))", x.name)
return
}
switch x := p.symtab[d.Name().String()].(type) {
case *tld:
p.w("uintptr(unsafe.Pointer(&%s))", x.name)
case *imported:
x.used = true
p.w("uintptr(unsafe.Pointer(&%sX%s))", x.qualifier, d.Name())
default:
panic(todo("%v: %v: %q", n.Position(), p.pos(d), d.Name()))
}
}
func (p *project) convertType(n cc.Node, from, to cc.Type, flags flags) string {
// trc("%v: %v: %v -> %v %v", n.Position(), origin(1), from, to, flags) //TODO- DBG
if from != nil {
switch from.Kind() {
case cc.Int128:
return p.convertTypeFromInt128(n, to, flags)
case cc.UInt128:
return p.convertTypeFromUint128(n, to, flags)
}
}
switch to.Kind() {
case cc.Int128:
return p.convertTypeToInt128(n, from, flags)
case cc.UInt128:
return p.convertTypeToUint128(n, from, flags)
}
// trc("%v: %v -> %v\n%s", p.pos(n), from, to, debug.Stack()[:600]) //TODO-
force := flags&fForceConv != 0
if from == nil {
p.w("%s(", p.typ(n, to))
return ")"
}
if from.IsScalarType() {
switch {
case force:
p.w("%s(", p.helperType2(n, from, to))
return ")"
case from.Kind() == to.Kind():
return ""
default:
p.w("%s(", p.typ(n, to))
return ")"
}
}
switch from.Kind() {
case cc.Function, cc.Struct, cc.Union, cc.Ptr, cc.Array:
if from.Kind() == to.Kind() {
return ""
}
panic(todo("", n.Position(), from, to, from.Alias(), to.Alias()))
case cc.Double, cc.Float:
p.w("%s(", p.typ(n, to))
return ")"
}
panic(todo("", n.Position(), from, to, from.Alias(), to.Alias()))
}
func (p *project) convertTypeFromInt128(n cc.Node, to cc.Type, flags flags) string {
switch k := to.Kind(); {
case k == cc.Float, k == cc.Double:
p.w("(")
return fmt.Sprintf(").Float%d()", to.Size()*8)
case k == cc.Int128:
return ""
case k == cc.UInt128:
p.w("%sUint128FromInt128(", p.task.crt)
return ")"
case to.IsIntegerType() && to.IsSignedType():
p.w("int%d((", to.Size()*8)
return ").Lo)"
case to.IsIntegerType() && !to.IsSignedType():
p.w("uint%d((", to.Size()*8)
return ").Lo)"
default:
panic(todo("", n.Position(), to, to.Alias()))
}
}
func (p *project) convertTypeFromUint128(n cc.Node, to cc.Type, flags flags) string {
switch k := to.Kind(); {
case k == cc.Float, k == cc.Double:
p.w("(")
return fmt.Sprintf(").Float%d()", to.Size()*8)
case k == cc.Int128:
p.w("(")
return ").Int128()"
case k == cc.UInt128:
return ""
case to.IsIntegerType() && to.IsSignedType():
p.w("int%d((", to.Size()*8)
return ").Lo)"
case to.IsIntegerType() && !to.IsSignedType():
p.w("uint%d((", to.Size()*8)
return ").Lo)"
default:
panic(todo("", n.Position(), to, to.Alias()))
}
}
func (p *project) convertTypeToInt128(n cc.Node, from cc.Type, flags flags) string {
switch k := from.Kind(); {
case k == cc.Float, k == cc.Double:
p.w("%sInt128FromFloat%d(", p.task.crt, from.Size()*8)
return ")"
case k == cc.Int128:
return ""
case k == cc.UInt128:
p.w("%sInt128FromUint128(", p.task.crt)
return ")"
case from.IsIntegerType() && from.IsSignedType():
p.w("%sInt128FromInt%d(", p.task.crt, from.Size()*8)
return ")"
case from.IsIntegerType() && !from.IsSignedType():
p.w("%sInt128FromUint%d(", p.task.crt, from.Size()*8)
return ")"
default:
panic(todo("", n.Position(), from, from.Alias()))
}
}
func (p *project) convertTypeToUint128(n cc.Node, from cc.Type, flags flags) string {
switch k := from.Kind(); {
case k == cc.Float, k == cc.Double:
p.w("%sUint128FromFloat%d(", p.task.crt, from.Size()*8)
return ")"
case k == cc.Int128:
p.w("(")
return ").Uint128()"
case k == cc.UInt128:
return ""
case from.IsIntegerType() && from.IsSignedType():
p.w("%sUint128FromInt%d(", p.task.crt, from.Size()*8)
return ")"
case from.IsIntegerType() && !from.IsSignedType():
p.w("%sUint128FromUint%d(", p.task.crt, from.Size()*8)
return ")"
default:
panic(todo("", n.Position(), from, from.Alias()))
}
}
func (p *project) convertFromInt128(n cc.Node, op cc.Operand, to cc.Type, flags flags) string {
switch k := to.Kind(); {
case k == cc.Float, k == cc.Double:
p.w("(")
return fmt.Sprintf(").Float%d()", to.Size()*8)
case k == cc.Int128:
return ""
case k == cc.UInt128:
p.w("(")
return ").Uint128()"
case to.IsIntegerType() && to.IsSignedType():
p.w("%sInt%d(", p.task.crt, to.Size()*8)
return ")"
case to.IsIntegerType() && !to.IsSignedType():
p.w("%sUint%d(", p.task.crt, to.Size()*8)
return ")"
default:
panic(todo("", n.Position(), to, to.Alias()))
}
}
func (p *project) convertFromUint128(n cc.Node, op cc.Operand, to cc.Type, flags flags) string {
switch k := to.Kind(); {
case k == cc.Float, k == cc.Double:
p.w("%sUint128FromFloat%d(", p.task.crt, to.Size()*8)
return ")"
case k == cc.Int128:
p.w("(")
return ").Int128()"
case k == cc.UInt128:
return ""
case to.IsIntegerType() && to.IsSignedType():
p.w("%sInt%d(", p.task.crt, to.Size()*8)
return ")"
case to.IsIntegerType() && !to.IsSignedType():
p.w("%sUint%d(", p.task.crt, to.Size()*8)
return ")"
default:
panic(todo("", n.Position(), to, to.Alias()))
}
}
func (p *project) convertToInt128(n cc.Node, op cc.Operand, to cc.Type, flags flags) string {
from := op.Type()
switch k := from.Kind(); {
case k == cc.Float, k == cc.Double:
p.w("%sInt128FromFloat%d(", p.task.crt, from.Size()*8)
return ")"
case k == cc.Int128:
return ""
case k == cc.UInt128:
p.w("(")
return ").Int128()"
case from.IsIntegerType() && from.IsSignedType():
p.w("%sInt128FromInt%d(", p.task.crt, from.Size()*8)
return ")"
case from.IsIntegerType() && !from.IsSignedType():
p.w("%sInt128FromUint%d(", p.task.crt, from.Size()*8)
return ")"
default:
panic(todo("", n.Position(), from, from.Alias()))
}
}
func (p *project) convertToUint128(n cc.Node, op cc.Operand, to cc.Type, flags flags) string {
from := op.Type()
switch k := from.Kind(); {
case k == cc.Float, k == cc.Double:
p.w("%sUint128FromFloat%d(", p.task.crt, from.Size()*8)
return ")"
case k == cc.Int128:
p.w("(")
return ").Uint128()"
case k == cc.UInt128:
return ""
case from.IsIntegerType() && from.IsSignedType():
p.w("%sUint128FromInt%d(", p.task.crt, from.Size()*8)
return ")"
case from.IsIntegerType() && !from.IsSignedType():
p.w("%sUint128FromUint%d(", p.task.crt, from.Size()*8)
return ")"
default:
panic(todo("", n.Position(), from, from.Alias()))
}
}
func (p *project) convertNil(n cc.Node, to cc.Type, flags flags) string {
switch to.Kind() {
case cc.Int128:
panic(todo("", p.pos(n)))
case cc.UInt128:
panic(todo("", p.pos(n)))
}
p.w("%s(", p.typ(n, to))
return ")"
}
func (p *project) convert(n cc.Node, op cc.Operand, to cc.Type, flags flags) string {
if op == nil {
panic(todo("internal error"))
}
from := op.Type()
switch from.Kind() {
case cc.Int128:
return p.convertFromInt128(n, op, to, flags)
case cc.UInt128:
return p.convertFromUint128(n, op, to, flags)
}
switch to.Kind() {
case cc.Int128:
return p.convertToInt128(n, op, to, flags)
case cc.UInt128:
return p.convertToUint128(n, op, to, flags)
}
if flags&fForceRuntimeConv != 0 {
flags |= fForceConv
}
force := flags&fForceConv != 0
if !force && from.IsScalarType() && from.Kind() == to.Kind() {
return ""
}
if from.IsIntegerType() {
return p.convertInt(n, op, to, flags)
}
if from == to {
return ""
}
switch from.Kind() {
case cc.Ptr:
if !force && from.Kind() == to.Kind() {
return ""
}
if to.IsIntegerType() {
p.w("%s(", p.typ(n, to))
return ")"
}
if to.Kind() == cc.Ptr {
return ""
}
panic(todo("%v: force %v, %q %v -> %q %v", p.pos(n), force, from, from.Kind(), to, to.Kind()))
case cc.Function, cc.Struct, cc.Union:
if !force && from.Kind() == to.Kind() {
return ""
}
trc("%p %p", from, to)
panic(todo("%q %v -> %q %v", from, from.Kind(), to, to.Kind()))
case cc.Double, cc.Float:
switch {
case to.IsIntegerType():
p.w("%s(", p.helperType2(n, from, to))
return ")"
default:
p.w("%s(", p.typ(n, to))
return ")"
}
case cc.Array:
if from.Kind() == to.Kind() {
return ""
}
switch to.Kind() {
case cc.Ptr:
return ""
}
panic(todo("%q, %v -> %q, %v", from, from.Kind(), to.Kind()))
}
panic(todo("%q -> %q", from, to))
}
func (p *project) convertInt(n cc.Node, op cc.Operand, to cc.Type, flags flags) string {
from := op.Type()
switch from.Kind() {
case cc.Int128:
panic(todo("", p.pos(n)))
case cc.UInt128:
panic(todo("", p.pos(n)))
}
switch to.Kind() {
case cc.Int128:
panic(todo("", p.pos(n)))
case cc.UInt128:
panic(todo("", p.pos(n)))
}
force := flags&fForceConv != 0
value := op.Value()
if value == nil || !to.IsIntegerType() {
if to.IsScalarType() {
p.w("%s(", p.typ(n, to))
return ")"
}
panic(todo("", op.Type(), to))
}
if flags&fForceRuntimeConv != 0 {
p.w("%s(", p.helperType2(n, op.Type(), to))
return ")"
}
switch {
case from.IsSignedType():
switch {
case to.IsSignedType():
switch x := value.(type) {
case cc.Int64Value:
switch to.Size() {
case 1:
if x >= math.MinInt8 && x <= math.MaxInt8 {
switch {
case !force && from.Size() == to.Size():
return ""
default:
p.w("int8(")
return ")"
}
}
p.w("%sInt8FromInt%d(", p.task.crt, from.Size()*8)
return ")"
case 2:
if x >= math.MinInt16 && x <= math.MaxInt16 {
switch {
case !force && from.Size() == to.Size():
return ""
default:
p.w("int16(")
return ")"
}
}
p.w("%sInt16FromInt%d(", p.task.crt, from.Size()*8)
return ")"
case 4:
if x >= math.MinInt32 && x <= math.MaxInt32 {
switch {
case !force && from.Size() == to.Size():
return ""
default:
p.w("int32(")
return ")"
}
}
p.w("%sInt32FromInt%d(", p.task.crt, from.Size()*8)
return ")"
case 8:
switch {
case !force && from.Size() == to.Size():
return ""
default:
p.w("int64(")
return ")"
}
default:
panic(todo("%T(%v) %v -> %v", x, op.Value(), from, to))
}
default:
panic(todo("%T(%v) %v -> %v", x, op.Value(), from, to))
}
default: // to is unsigned
switch x := value.(type) {
case cc.Int64Value:
switch to.Size() {
case 1:
if x >= 0 && x <= math.MaxUint8 {
p.w("%s(", p.typ(n, to))
return ")"
}
p.w("%sUint8FromInt%d(", p.task.crt, from.Size()*8)
return ")"
case 2:
if x >= 0 && x <= math.MaxUint16 {
p.w("%s(", p.typ(n, to))
return ")"
}
p.w("%sUint16FromInt%d(", p.task.crt, from.Size()*8)
return ")"
case 4:
if x >= 0 && x <= math.MaxUint32 {
p.w("%s(", p.typ(n, to))
return ")"
}
p.w("%sUint32FromInt%d(", p.task.crt, from.Size()*8)
return ")"
case 8:
if x >= 0 {
p.w("uint64(")
return ")"
}
p.w("%sUint64FromInt%d(", p.task.crt, from.Size()*8)
return ")"
default:
panic(todo("%T(%v) %v -> %v", x, op.Value(), from, to))
}
case cc.Uint64Value:
switch to.Size() {
case 1:
if x <= math.MaxUint8 {
p.w("%s(", p.typ(n, to))
return ")"
}
p.w("%sUint8FromUint%d(", p.task.crt, from.Size()*8)
return ")"
case 2:
if x <= math.MaxUint16 {
p.w("%s(", p.typ(n, to))
return ")"
}
p.w("%sUint16FromUint%d(", p.task.crt, from.Size()*8)
return ")"
case 4:
if x <= math.MaxUint32 {
p.w("%s(", p.typ(n, to))
return ")"
}
p.w("%sUint32FromUint%d(", p.task.crt, from.Size()*8)
return ")"
case 8:
p.w("uint64(")
return ")"
default:
panic(todo("%T(%v) %v -> %v", x, op.Value(), from, to))
}
default:
panic(todo("%T(%v) %v -> %v", x, op.Value(), from, to))
}
}
default: // from is unsigned
switch {
case to.IsSignedType():
switch x := value.(type) {
case cc.Uint64Value:
switch to.Size() {
case 1:
if x <= math.MaxInt8 {
p.w("int8(")
return ")"
}
p.w("%sInt8FromUint%d(", p.task.crt, from.Size()*8)
return ")"
case 2:
if x <= math.MaxInt16 {
p.w("int16(")
return ")"
}
p.w("%sInt16FromUint%d(", p.task.crt, from.Size()*8)
return ")"
case 4:
if x <= math.MaxInt32 {
p.w("int32(")
return ")"
}
p.w("%sInt32FromUint%d(", p.task.crt, from.Size()*8)
return ")"
case 8:
if x <= math.MaxInt64 {
p.w("int64(")
return ")"
}
p.w("%sInt64FromUint%d(", p.task.crt, from.Size()*8)
return ")"
default:
panic(todo("%T(%v) %v -> %v", x, op.Value(), from, to))
}
default:
panic(todo("%T(%v) %v -> %v", x, op.Value(), from, to))
}
default: // to is unsigned
switch x := value.(type) {
case cc.Uint64Value:
switch to.Size() {
case 1:
if x <= math.MaxUint8 {
switch {
case !force && from.Size() == 1:
return ""
default:
p.w("uint8(")
return ")"
}
}
p.w("%sUint8FromUint%d(", p.task.crt, from.Size()*8)
return ")"
case 2:
if x <= math.MaxUint16 {
switch {
case !force && from.Size() == 2:
return ""
default:
p.w("uint16(")
return ")"
}
}
p.w("%sUint16FromUint%d(", p.task.crt, from.Size()*8)
return ")"
case 4:
if x <= math.MaxUint32 {
switch {
case !force && from.Size() == 4:
return ""
default:
p.w("uint32(")
return ")"
}
}
p.w("%sUint32FromUint%d(", p.task.crt, from.Size()*8)
return ")"
case 8:
switch {
case !force && from.Size() == 8:
return ""
default:
p.w("uint64(")
return ")"
}
default:
panic(todo("%T(%v) %v -> %v", x, op.Value(), from, to))
}
default:
panic(todo("%T(%v) %v -> %v", x, op.Value(), from, to))
}
}
}
}
func nonZeroUintptr(n uintptr) string {
if n == 0 {
return ""
}
return fmt.Sprintf("%+d", n)
}
func alias(attr []*cc.AttributeSpecifier) (r cc.StringID) {
for _, v := range attr {
cc.Inspect(v, func(n cc.Node, entry bool) bool {
if !entry {
return true
}
if x, ok := n.(*cc.AttributeValue); ok && x.Token.Value == idAlias {
switch y := x.ExpressionList.AssignmentExpression.Operand.Value().(type) {
case cc.StringValue:
r = cc.StringID(y)
return false
}
}
return true
})
if r != 0 {
return r
}
}
return 0
}
func (p *project) tld(f *function, n *cc.InitDeclarator, sep string, staticLocal bool) {
d := n.Declarator
if d.IsExtern() && d.Linkage == cc.External && !d.IsTypedefName {
if alias := alias(attrs(d.Type())); alias != 0 {
p.capi = append(p.capi, d.Name().String())
p.w("\n\nvar %s%s = %s\t// %v:\n", p.task.exportExterns, d.Name(), p.externs[alias].name, p.pos(d))
return
}
}
if _, ok := p.wanted[d]; !ok && !staticLocal {
isFn := d.Type().Kind() == cc.Function
if isFn && p.task.header && p.task.funcSig {
if nm := d.Name().String(); !strings.HasPrefix(nm, "__") {
p.w("\n\n")
t := p.tlds[d]
if t == nil {
t = &tld{}
t.name = p.tldScope.take(d.Name())
}
p.functionSignature2(n, nil, d.Type(), t.name)
}
}
return
}
tld := p.tlds[d]
if tld == nil { // Dead declaration.
return
}
t := d.Type()
if d.IsTypedefName {
p.checkAttributes(t)
if _, ok := p.typedefsEmited[tld.name]; ok {
return
}
p.typedefsEmited[tld.name] = struct{}{}
if t.Kind() != cc.Void {
p.w("%stype %s = %s; /* %v */", sep, tld.name, p.typ(n, t), p.pos(d))
}
return
}
switch n.Case {
case cc.InitDeclaratorDecl: // Declarator AttributeSpecifierList
p.w("%svar %s %s\t/* %v: */", sep, tld.name, p.typ(n, t), p.pos(n))
switch t.Kind() {
case cc.Struct, cc.Union:
p.structs[t.Tag()].emit(p, nil)
}
case cc.InitDeclaratorInit: // Declarator AttributeSpecifierList '=' Initializer
if d.IsStatic() && d.Read == 0 && d.Write == 1 && n.Initializer.IsConst() { // Initialized with no side effects and unused.
break
}
p.w("%svar %s ", sep, tld.name)
if !isAggregateTypeOrUnion(d.Type()) {
p.w("%s ", p.typ(n, d.Type()))
}
p.w("= ")
p.initializer(f, n.Initializer, d.Type(), d.StorageClass, tld)
p.w("; /* %v */", p.pos(d))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) functionDefinition(n *cc.FunctionDefinition) {
// DeclarationSpecifiers Declarator DeclarationList CompoundStatement
if p.task.header && !p.task.funcSig {
return
}
if _, ok := p.sharedFns[n]; ok {
if _, ok := p.sharedFnsEmitted[n]; ok {
return
}
p.sharedFnsEmitted[n] = struct{}{}
}
d := n.Declarator
if d.IsExtern() && d.Type().Inline() {
// https://gcc.gnu.org/onlinedocs/gcc/Inline.html
//
// If you specify both inline and extern in the function definition, then the
// definition is used only for inlining. In no case is the function compiled on
// its own, not even if you refer to its address explicitly. Such an address
// becomes an external reference, as if you had only declared the function, and
// had not defined it.
//
// This combination of inline and extern has almost the effect of a macro. The
// way to use it is to put a function definition in a header file with these
// keywords, and put another copy of the definition (lacking inline and extern)
// in a library file. The definition in the header file causes most calls to
// the function to be inlined. If any uses of the function remain, they refer
// to the single copy in the library.
return
}
name := d.Name().String()
if _, ok := p.task.hide[name]; ok {
return
}
if p.isMain && d.Linkage == cc.External && d.Read == 0 && !d.AddressTaken && len(p.task.asts) == 1 {
return
}
if d.Linkage == cc.Internal && d.Read == 0 && !d.AddressTaken /*TODO- && strings.HasPrefix(name, "__") */ {
return
}
tld := p.tlds[d]
if tld == nil {
return
}
p.fn = name
defer func() { p.fn = "" }()
f := newFunction(p, n)
p.pass1 = true
p.compoundStatement(f, n.CompoundStatement, "", false, false, 0)
p.pass1 = false
p.w("\n\n")
p.functionDefinitionSignature(n, f, tld)
if p.task.header && p.task.funcSig {
return
}
p.w(" ")
comment := fmt.Sprintf("/* %v: */", p.pos(d))
if p.task.panicStubs {
p.w("%s{ panic(%q) }", comment, tld.name)
return
}
brace := "{"
if need := f.off; need != 0 {
scope := f.blocks[n.CompoundStatement].scope
f.bpName = scope.take(idBp)
p.w("{%s\n%s := %s.Alloc(%d)\n", comment, f.bpName, f.tlsName, need)
p.w("defer %s.Free(%d)\n", f.tlsName, need)
for _, v := range d.Type().Parameters() {
if local := f.locals[v.Declarator()]; local != nil && local.isPinned { // Pin it.
p.w("*(*%s)(unsafe.Pointer(%s%s)) = %s\n", p.typ(v.Declarator(), paramTypeDecay(v.Declarator())), f.bpName, nonZeroUintptr(local.off), local.name)
}
}
comment = ""
brace = ""
}
if len(f.vlas) != 0 {
p.w("%s%s\n", brace, comment)
var vlas []*cc.Declarator
for k := range f.vlas {
vlas = append(vlas, k)
}
sort.Slice(vlas, func(i, j int) bool {
return vlas[i].NameTok().Seq() < vlas[j].NameTok().Seq()
})
for _, v := range vlas {
local := f.locals[v]
switch {
case local.isPinned:
panic(todo("", v.Position()))
default:
p.w("var %s uintptr // %v: %v\n", local.name, p.pos(v), v.Type())
}
}
switch {
case len(vlas) == 1:
p.w("defer %sXfree(%s, %s)\n", p.task.crt, f.tlsName, f.locals[vlas[0]].name)
default:
p.w("defer func() {\n")
for _, v := range vlas {
p.w("%sXfree(%s, %s)\n", p.task.crt, f.tlsName, f.locals[v].name)
}
p.w("\n}()\n")
}
}
p.compoundStatement(f, n.CompoundStatement, comment, false, true, 0)
p.w(";")
p.flushLocalTaggesStructs()
p.flushStaticTLDs()
}
func (p *project) flushLocalTaggesStructs() {
for _, v := range p.localTaggedStructs {
v()
}
p.localTaggedStructs = nil
}
func (p *project) flushStaticTLDs() {
for _, v := range p.staticQueue {
p.tld(nil, v, "\n", true)
}
p.staticQueue = nil
}
func (p *project) compoundStatement(f *function, n *cc.CompoundStatement, scomment string, forceNoBraces, fnBody bool, mode exprMode) {
if p.task.panicStubs {
return
}
// '{' BlockItemList '}'
brace := (!n.IsJumpTarget() || n.Parent() == nil) && !forceNoBraces
if brace && len(f.vlas) == 0 && (n.Parent() != nil || f.off == 0) {
p.w("{%s", scomment)
}
if fnBody {
p.instrument(n)
}
sv := f.block
f.block = f.blocks[n]
if f.block.topDecl {
for _, v := range f.block.decls {
p.declaration(f, v, true)
}
}
var r *cc.JumpStatement
for list := n.BlockItemList; list != nil; list = list.BlockItemList {
m := mode
if list.BlockItemList != nil {
m = 0
}
r = p.blockItem(f, list.BlockItem, m)
}
if n.Parent() == nil && r == nil && f.rt.Kind() != cc.Void {
p.w("\nreturn ")
p.zeroValue(n, f.rt)
}
s := tidyComment("\n", &n.Token2)
p.w("%s", s)
if brace {
if !strings.HasSuffix(s, "\n") {
p.w("\n")
}
p.w("}")
}
f.block = sv
}
func (p *project) zeroValue(n cc.Node, t cc.Type) {
if t.IsScalarType() {
p.w("%s(0)", p.typ(n, t))
return
}
switch t.Kind() {
case cc.Struct, cc.Union:
p.w("%s{}", p.typ(n, t))
default:
panic(todo("", t, t.Kind()))
}
}
func (p *project) blockItem(f *function, n *cc.BlockItem, mode exprMode) (r *cc.JumpStatement) {
switch n.Case {
case cc.BlockItemDecl: // Declaration
p.declaration(f, n.Declaration, false)
case cc.BlockItemStmt: // Statement
r = p.statement(f, n.Statement, false, false, false, mode)
p.w(";")
if r == nil {
p.instrument(n)
}
case cc.BlockItemLabel: // LabelDeclaration
panic(todo("", p.pos(n)))
p.w(";")
case cc.BlockItemFuncDef: // DeclarationSpecifiers Declarator CompoundStatement
p.err(n, "nested functions not supported")
p.w(";")
case cc.BlockItemPragma: // PragmaSTDC
panic(todo("", p.pos(n)))
p.w(";")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
return r
}
func (p *project) instrument(n cc.Node) {
if p.task.cover {
p.w("%sCover();", p.task.crt)
}
if p.task.coverC {
p.w("%sCoverC(%q);", p.task.crt, p.pos(n).String()+" "+p.fn)
}
if p.task.watch {
p.w("%sWatch();", p.task.crt)
}
}
var dummyJumpStatement = &cc.JumpStatement{}
func (p *project) statement(f *function, n *cc.Statement, forceCompoundStmtBrace, forceNoBraces, switchBlock bool, mode exprMode) (r *cc.JumpStatement) {
if forceCompoundStmtBrace {
if f.switchCtx == inSwitchFirst && p.pauseCodegen {
p.pauseCodegen = false
p.w(" {")
p.pauseCodegen = true
}
p.w(" {")
if !switchBlock {
p.instrument(n)
}
}
switch n.Case {
case cc.StatementLabeled: // LabeledStatement
r = p.labeledStatement(f, n.LabeledStatement)
case cc.StatementCompound: // CompoundStatement
if !forceCompoundStmtBrace {
p.w("%s", n.CompoundStatement.Token.Sep)
}
if f.hasJumps {
forceNoBraces = true
}
p.compoundStatement(f, n.CompoundStatement, "", forceCompoundStmtBrace || forceNoBraces, false, 0)
case cc.StatementExpr: // ExpressionStatement
if mode != 0 {
p.w("return ")
e := n.ExpressionStatement.Expression
p.expression(f, e, e.Operand.Type(), exprValue, 0)
r = dummyJumpStatement
break
}
p.expressionStatement(f, n.ExpressionStatement)
case cc.StatementSelection: // SelectionStatement
p.selectionStatement(f, n.SelectionStatement)
case cc.StatementIteration: // IterationStatement
p.iterationStatement(f, n.IterationStatement)
case cc.StatementJump: // JumpStatement
r = p.jumpStatement(f, n.JumpStatement)
case cc.StatementAsm: // AsmStatement
// AsmStatement:
// Asm AttributeSpecifierList ';'
// Asm:
// "__asm__" AsmQualifierList '(' STRINGLITERAL AsmArgList ')'
if n.AsmStatement.Asm.Token3.Value == 0 && n.AsmStatement.Asm.AsmArgList == nil {
break
}
p.w("panic(`%s: assembler statements not supported`)", n.Position())
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
if forceCompoundStmtBrace {
// We need to do this, to guarantee that we always close the brace is we opened it
if f.switchCtx == inSwitchFirst && p.pauseCodegen {
p.pauseCodegen = false
p.w("}")
p.pauseCodegen = true
}
p.w("}")
}
return r
}
func (p *project) jumpStatement(f *function, n *cc.JumpStatement) (r *cc.JumpStatement) {
p.w("%s", tidyComment("\n", n))
if _, ok := n.Context().(*cc.SelectionStatement); ok && f.ifCtx == nil {
switch f.switchCtx {
case inSwitchCase:
f.switchCtx = inSwitchSeenBreak
case inSwitchSeenBreak:
// nop but TODO
case inSwitchFlat:
// ok
default:
panic(todo("", n.Position(), f.switchCtx))
}
}
switch n.Case {
case cc.JumpStatementGoto: // "goto" IDENTIFIER ';'
p.w("goto %s", f.labelNames[n.Token2.Value])
case cc.JumpStatementGotoExpr: // "goto" '*' Expression ';'
panic(todo("", p.pos(n)))
case cc.JumpStatementContinue: // "continue" ';'
switch {
case f.continueCtx != 0:
p.w("goto __%d", f.continueCtx)
default:
p.w("continue")
}
case cc.JumpStatementBreak: // "break" ';'
switch {
case f.breakCtx != 0:
p.w("goto __%d", f.breakCtx)
default:
p.w("break")
}
case cc.JumpStatementReturn: // "return" Expression ';'
r = n
switch {
case f.rt != nil && f.rt.Kind() == cc.Void:
if n.Expression != nil {
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprVoid, 0)
p.w(";")
}
p.w("return")
case f.rt != nil && f.rt.Kind() != cc.Void:
if n.Expression != nil {
p.expression(f, n.Expression, f.rt, exprCondReturn, 0)
break
}
p.w("return ")
p.zeroValue(n, f.rt)
default:
if n.Expression != nil {
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprVoid, 0)
p.w(";")
}
p.w("return")
}
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
return r
}
func (p *project) expression(f *function, n *cc.Expression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprVoid:
p.expressionVoid(f, n, t, mode, flags)
case exprValue, exprCondReturn, exprCondInit:
p.expressionValue(f, n, t, mode, flags)
case exprBool:
p.expressionBool(f, n, t, mode, flags)
case exprAddrOf:
p.expressionAddrOf(f, n, t, mode, flags)
case exprPSelect:
p.expressionPSelect(f, n, t, mode, flags)
case exprLValue:
p.expressionLValue(f, n, t, mode, flags)
case exprFunc:
p.expressionFunc(f, n, t, mode, flags)
case exprSelect:
p.expressionSelect(f, n, t, mode, flags)
case exprDecay:
p.expressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) expressionDecay(f *function, n *cc.Expression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExpressionAssign: // AssignmentExpression
p.assignmentExpression(f, n.AssignmentExpression, t, mode, flags)
case cc.ExpressionComma: // Expression ',' AssignmentExpression
p.w("func() uintptr {")
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprVoid, flags)
p.w("; return ")
p.assignmentExpression(f, n.AssignmentExpression, t, mode, flags)
p.w("}()")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) expressionSelect(f *function, n *cc.Expression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExpressionAssign: // AssignmentExpression
p.assignmentExpression(f, n.AssignmentExpression, t, mode, flags)
case cc.ExpressionComma: // Expression ',' AssignmentExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) expressionFunc(f *function, n *cc.Expression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExpressionAssign: // AssignmentExpression
p.assignmentExpression(f, n.AssignmentExpression, t, mode, flags)
case cc.ExpressionComma: // Expression ',' AssignmentExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) expressionLValue(f *function, n *cc.Expression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExpressionAssign: // AssignmentExpression
p.assignmentExpression(f, n.AssignmentExpression, t, mode, flags)
case cc.ExpressionComma: // Expression ',' AssignmentExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) expressionPSelect(f *function, n *cc.Expression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExpressionAssign: // AssignmentExpression
p.assignmentExpression(f, n.AssignmentExpression, t, mode, flags)
case cc.ExpressionComma: // Expression ',' AssignmentExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) expressionAddrOf(f *function, n *cc.Expression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExpressionAssign: // AssignmentExpression
p.assignmentExpression(f, n.AssignmentExpression, t, mode, flags)
case cc.ExpressionComma: // Expression ',' AssignmentExpression
p.w(" func() uintptr {")
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprVoid, flags)
p.w("; return ")
p.assignmentExpression(f, n.AssignmentExpression, t, mode, flags)
p.w("}()")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) expressionBool(f *function, n *cc.Expression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExpressionAssign: // AssignmentExpression
p.assignmentExpression(f, n.AssignmentExpression, t, mode, flags)
case cc.ExpressionComma: // Expression ',' AssignmentExpression
p.w("func() bool {")
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprVoid, flags)
p.w("; return ")
p.assignmentExpression(f, n.AssignmentExpression, n.AssignmentExpression.Operand.Type(), mode, flags)
p.w("}()")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) expressionValue(f *function, n *cc.Expression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExpressionAssign: // AssignmentExpression
p.assignmentExpression(f, n.AssignmentExpression, t, mode, flags)
case cc.ExpressionComma: // Expression ',' AssignmentExpression
if mode == exprCondReturn {
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprVoid, flags)
p.w("; return ")
p.assignmentExpression(f, n.AssignmentExpression, n.AssignmentExpression.Operand.Type(), exprValue, flags)
return
}
switch {
case n.AssignmentExpression.Operand.Type().Kind() == cc.Array:
p.expressionDecay(f, n, t, exprDecay, flags)
default:
defer p.w("%s", p.convertType(n, n.Operand.Type(), t, flags))
p.w("func() %v {", p.typ(n, n.AssignmentExpression.Operand.Type()))
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprVoid, flags)
p.w("; return ")
p.assignmentExpression(f, n.AssignmentExpression, n.AssignmentExpression.Operand.Type(), exprValue, flags)
p.w("}()")
}
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) expressionVoid(f *function, n *cc.Expression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExpressionAssign: // AssignmentExpression
p.assignmentExpression(f, n.AssignmentExpression, t, mode, flags)
case cc.ExpressionComma: // Expression ',' AssignmentExpression
p.expression(f, n.Expression, t, mode, flags)
p.w(";")
p.assignmentExpression(f, n.AssignmentExpression, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) opKind(f *function, d declarator, t cc.Type) opKind {
switch {
case p.isArrayParameter(d, t):
return opArrayParameter
case !p.pass1 && p.isArray(f, d, t):
return opArray
case t.Kind() == cc.Union:
return opUnion
case t.Kind() == cc.Struct:
return opStruct
case t.IsBitFieldType():
return opBitfield
case t.Kind() == cc.Function:
return opFunction
default:
return opNormal
}
}
func (p *project) assignmentExpression(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprVoid:
p.assignmentExpressionVoid(f, n, t, mode, flags)
case exprValue, exprCondReturn, exprCondInit:
p.assignmentExpressionValue(f, n, t, mode, flags)
case exprAddrOf:
p.assignmentExpressionAddrOf(f, n, t, mode, flags)
case exprBool:
p.assignmentExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.assignmentExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.assignmentExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.assignmentExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.assignmentExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.assignmentExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) assignmentExpressionDecay(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AssignmentExpressionCond: // ConditionalExpression
p.conditionalExpression(f, n.ConditionalExpression, t, mode, flags)
case cc.AssignmentExpressionAssign: // UnaryExpression '=' AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionMul: // UnaryExpression "*=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionDiv: // UnaryExpression "/=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionMod: // UnaryExpression "%=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionAdd: // UnaryExpression "+=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionSub: // UnaryExpression "-=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionLsh: // UnaryExpression "<<= AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionRsh: // UnaryExpression ">>=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionAnd: // UnaryExpression "&=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionXor: // UnaryExpression "^=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionOr: // UnaryExpression "|=" AssignmentExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) assignmentExpressionSelect(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AssignmentExpressionCond: // ConditionalExpression
p.conditionalExpression(f, n.ConditionalExpression, t, mode, flags)
case cc.AssignmentExpressionAssign: // UnaryExpression '=' AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionMul: // UnaryExpression "*=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionDiv: // UnaryExpression "/=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionMod: // UnaryExpression "%=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionAdd: // UnaryExpression "+=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionSub: // UnaryExpression "-=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionLsh: // UnaryExpression "<<=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionRsh: // UnaryExpression ">>=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionAnd: // UnaryExpression "&=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionXor: // UnaryExpression "^=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionOr: // UnaryExpression "|=" AssignmentExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) assignmentExpressionFunc(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AssignmentExpressionCond: // ConditionalExpression
p.conditionalExpression(f, n.ConditionalExpression, t, mode, flags)
case cc.AssignmentExpressionAssign: // UnaryExpression '=' AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionMul: // UnaryExpression "*=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionDiv: // UnaryExpression "/=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionMod: // UnaryExpression "%=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionAdd: // UnaryExpression "+=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionSub: // UnaryExpression "-=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionLsh: // UnaryExpremode, ssion "<<=
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionRsh: // UnaryExpression ">>=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionAnd: // UnaryExpression "&=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionXor: // UnaryExpression "^=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionOr: // UnaryExpression "|=" AssignmentExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) assignmentExpressionPSelect(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AssignmentExpressionCond: // ConditionalExpression
p.conditionalExpression(f, n.ConditionalExpression, t, mode, flags)
case cc.AssignmentExpressionAssign: // UnaryExpression '=' AssignmentExpression
p.w("(*%s)(unsafe.Pointer(", p.typ(n, n.AssignmentExpression.Operand.Type().Elem()))
p.assignmentExpression(f, n, t, exprValue, flags)
p.w("))")
case cc.AssignmentExpressionMul: // UnaryExpression "*=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionDiv: // UnaryExpression "/=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionMod: // UnaryExpression "%=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionAdd: // UnaryExpression "+=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionSub: // UnaryExpression "-=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionLsh: // UnaryExpression "<<=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionRsh: // UnaryExpression ">>=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionAnd: // UnaryExpression "&=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionXor: // UnaryExpression "^=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionOr: // UnaryExpression "|=" AssignmentExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) assignmentExpressionLValue(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AssignmentExpressionCond: // ConditionalExpression
p.conditionalExpression(f, n.ConditionalExpression, t, mode, flags)
case cc.AssignmentExpressionAssign: // UnaryExpression '=' AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionMul: // UnaryExpression "*=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionDiv: // UnaryExpression "/=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionMod: // UnaryExpression "%=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionAdd: // UnaryExpression "+=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionSub: // UnaryExpression "-=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionLsh: // UnaryExpression "<<=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionRsh: // UnaryExpression ">>=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionAnd: // UnaryExpression "&=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionXor: // UnaryExpression "^=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionOr: // UnaryExpression "|=" AssignmentExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) assignmentExpressionBool(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AssignmentExpressionCond: // ConditionalExpression
p.conditionalExpression(f, n.ConditionalExpression, t, mode, flags)
default:
// case cc.AssignmentExpressionAssign: // UnaryExpression '=' AssignmentExpression
// case cc.AssignmentExpressionMul: // UnaryExpression "*=" AssignmentExpression
// case cc.AssignmentExpressionDiv: // UnaryExpression "/=" AssignmentExpression
// case cc.AssignmentExpressionMod: // UnaryExpression "%=" AssignmentExpression
// case cc.AssignmentExpressionAdd: // UnaryExpression "+=" AssignmentExpression
// case cc.AssignmentExpressionSub: // UnaryExpression "-=" AssignmentExpression
// case cc.AssignmentExpressionLsh: // UnaryExpression "<<=" AssignmentExpression
// case cc.AssignmentExpressionRsh: // UnaryExpression ">>=" AssignmentExpression
// case cc.AssignmentExpressionAnd: // UnaryExpression "&=" AssignmentExpression
// case cc.AssignmentExpressionXor: // UnaryExpression "^=" AssignmentExpression
// case cc.AssignmentExpressionOr: // UnaryExpression "|=" AssignmentExpression
p.w("(")
defer p.w(")")
defer p.w(" != 0 ")
p.assignmentExpression(f, n, t, exprValue, flags)
}
}
func (p *project) assignmentExpressionAddrOf(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AssignmentExpressionCond: // ConditionalExpression
p.conditionalExpression(f, n.ConditionalExpression, t, mode, flags)
case cc.AssignmentExpressionAssign: // UnaryExpression '=' AssignmentExpression
p.assignmentExpressionValueAddrOf(f, n, t, mode, flags)
case cc.AssignmentExpressionMul: // UnaryExpression "*=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionDiv: // UnaryExpression "/=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionMod: // UnaryExpression "%=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionAdd: // UnaryExpression "+=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionSub: // UnaryExpression "-=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionLsh: // UnaryExpression "<<=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionRsh: // UnaryExpression ">>=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionAnd: // UnaryExpression "&=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionXor: // UnaryExpression "^=" AssignmentExpression
panic(todo("", p.pos(n)))
case cc.AssignmentExpressionOr: // UnaryExpression "|=" AssignmentExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) assignmentExpressionValueAddrOf(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
// UnaryExpression '=' AssignmentExpression
if mode == exprCondReturn {
panic(todo("", p.pos(n)))
}
lhs := n.UnaryExpression
switch k := p.opKind(f, lhs, lhs.Operand.Type()); k {
case opStruct, opUnion:
p.assignmentExpressionValueAssignStructAddrof(f, n, n.Operand.Type(), mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) assignmentExpressionValueAssignStructAddrof(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
// UnaryExpression '=' AssignmentExpression
lhs := n.UnaryExpression.Operand.Type()
rhs := n.AssignmentExpression.Operand.Type()
if lhs.Kind() == cc.Array || rhs.Kind() == cc.Array {
panic(todo("", p.pos(n)))
}
if d := n.UnaryExpression.Declarator(); d != nil {
if local := f.locals[d]; local != nil {
if local.isPinned {
if !p.pass1 {
p.w("%sXmemmove(tls, ", p.task.crt)
p.unaryExpression(f, n.UnaryExpression, lhs, exprAddrOf, flags)
p.w(", ")
p.assignmentExpression(f, n.AssignmentExpression, rhs, exprAddrOf, flags)
p.w(", %d)", lhs.Size())
return
}
}
if !p.pass1 {
panic(todo("", p.pos(n)))
}
}
}
p.w("%sXmemmove(tls, ", p.task.crt)
p.unaryExpression(f, n.UnaryExpression, lhs, exprAddrOf, flags)
p.w(", ")
p.assignmentExpression(f, n.AssignmentExpression, rhs, exprAddrOf, flags)
p.w(", %d)", lhs.Size())
}
func (p *project) assignmentExpressionValue(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AssignmentExpressionCond: // ConditionalExpression
p.conditionalExpression(f, n.ConditionalExpression, t, mode, flags)
case cc.AssignmentExpressionAssign: // UnaryExpression '=' AssignmentExpression
p.assignmentExpressionValueAssign(f, n, t, mode, flags)
case cc.AssignmentExpressionMul: // UnaryExpression "*=" AssignmentExpression
p.assignOp(f, n, t, mode, "*", "Mul", flags)
case cc.AssignmentExpressionDiv: // UnaryExpression "/=" AssignmentExpression
p.assignOp(f, n, t, mode, "/", "Div", flags)
case cc.AssignmentExpressionMod: // UnaryExpression "%=" AssignmentExpression
p.assignOp(f, n, t, mode, "%", "Rem", flags)
case cc.AssignmentExpressionAdd: // UnaryExpression "+=" AssignmentExpression
p.assignOp(f, n, t, mode, "+", "Add", flags)
case cc.AssignmentExpressionSub: // UnaryExpression "-=" AssignmentExpression
p.assignOp(f, n, t, mode, "-", "Sub", flags)
case cc.AssignmentExpressionLsh: // UnaryExpremode, ssion "<<=
p.assignOp(f, n, t, mode, "<<", "Shl", flags)
case cc.AssignmentExpressionRsh: // UnaryExpression ">>=" AssignmentExpression
p.assignOp(f, n, t, mode, ">>", "Shr", flags)
case cc.AssignmentExpressionAnd: // UnaryExpression "&=" AssignmentExpression
p.assignOp(f, n, t, mode, "&", "And", flags)
case cc.AssignmentExpressionXor: // UnaryExpression "^=" AssignmentExpression
p.assignOp(f, n, t, mode, "^", "Xor", flags)
case cc.AssignmentExpressionOr: // UnaryExpression "|=" AssignmentExpression
p.assignOp(f, n, t, mode, "|", "Or", flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) assignmentExpressionValueAssign(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
// UnaryExpression '=' AssignmentExpression
if mode == exprCondReturn {
p.w("return ")
}
lhs := n.UnaryExpression
switch k := p.opKind(f, lhs, lhs.Operand.Type()); k {
case opNormal:
p.assignmentExpressionValueAssignNormal(f, n, t, mode, flags)
case opBitfield:
p.assignmentExpressionValueAssignBitfield(f, n, t, mode, flags)
case opStruct, opUnion:
p.assignmentExpressionValueAssignStruct(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) assignmentExpressionValueAssignStruct(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
// UnaryExpression '=' AssignmentExpression
lhs := n.UnaryExpression.Operand.Type()
rhs := n.AssignmentExpression.Operand.Type()
if lhs.Kind() == cc.Array || rhs.Kind() == cc.Array {
panic(todo("", p.pos(n)))
}
p.w(" func() %s { __v := ", p.typ(n, lhs))
p.assignmentExpression(f, n.AssignmentExpression, rhs, exprValue, flags)
p.w(";")
p.unaryExpression(f, n.UnaryExpression, lhs, exprLValue, flags)
p.w(" = __v; return __v}()")
}
func (p *project) assignmentExpressionValueAssignBitfield(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
if d := n.UnaryExpression.Declarator(); d != nil {
panic(todo("", p.pos(n)))
}
lhs := n.UnaryExpression
lt := lhs.Operand.Type()
bf := lt.BitField()
defer p.w("%s", p.convertType(n, lt, t, flags))
p.w("%sAssignBitFieldPtr%d%s(", p.task.crt, bf.BitFieldBlockWidth(), p.bfHelperType(lt))
p.unaryExpression(f, lhs, lt, exprAddrOf, flags)
p.w(", ")
p.assignmentExpression(f, n.AssignmentExpression, lt, exprValue, flags)
p.w(", %d, %d, %#x)", bf.BitFieldWidth(), bf.BitFieldOffset(), bf.Mask())
}
func (p *project) assignmentExpressionValueAssignNormal(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
if d := n.UnaryExpression.Declarator(); d != nil {
if !d.Type().IsScalarType() {
panic(todo("", p.pos(n)))
}
if local := f.locals[d]; local != nil {
if local.isPinned {
defer p.w(")%s", p.convertType(n, d.Type(), t, flags))
p.w("%sAssignPtr%s(", p.task.crt, p.helperType(d, d.Type()))
p.w("%s%s /* %s */", f.bpName, nonZeroUintptr(local.off), local.name)
p.w(", ")
p.assignmentExpression(f, n.AssignmentExpression, n.UnaryExpression.Operand.Type(), exprValue, flags)
return
}
defer p.w(")%s", p.convertType(n, d.Type(), t, flags))
p.w("%sAssign%s(&%s, ", p.task.crt, p.helperType(n, d.Type()), local.name)
p.assignmentExpression(f, n.AssignmentExpression, n.UnaryExpression.Operand.Type(), exprValue, flags)
return
}
}
defer p.w(")%s", p.convertType(n, n.UnaryExpression.Operand.Type(), t, flags))
p.w("%sAssignPtr%s(", p.task.crt, p.helperType(n, n.UnaryExpression.Operand.Type()))
p.unaryExpression(f, n.UnaryExpression, n.UnaryExpression.Operand.Type(), exprAddrOf, flags)
p.w(", ")
p.assignmentExpression(f, n.AssignmentExpression, n.UnaryExpression.Operand.Type(), exprValue, flags)
}
func (p *project) assignmentExpressionVoid(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AssignmentExpressionCond: // ConditionalExpression
p.conditionalExpression(f, n.ConditionalExpression, t, mode, flags)
case cc.AssignmentExpressionAssign: // UnaryExpression '=' AssignmentExpression
d := n.UnaryExpression.Declarator()
lhs := n.UnaryExpression
lt := lhs.Operand.Type()
sv := f.condInitPrefix
switch k := p.opKind(f, lhs, lt); k {
case opArrayParameter:
lt = lt.Decay()
fallthrough
case opNormal, opStruct:
mode = exprValue
if p.isArrayOrPinnedArray(f, n.AssignmentExpression, n.AssignmentExpression.Operand.Type()) {
mode = exprDecay
}
switch {
case flags&fNoCondAssignment == 0 && mode == exprValue && n.UnaryExpression.Declarator() != nil && p.isConditionalAssignmentExpr(n.AssignmentExpression):
f.condInitPrefix = func() {
p.unaryExpression(f, lhs, lt, exprLValue, flags)
p.w(" = ")
}
p.assignmentExpression(f, n.AssignmentExpression, lt, exprCondInit, flags)
p.w(";")
default:
if d != nil && p.isVolatileOrAtomic(d) {
p.setVolatileDeclarator(d, f, n.AssignmentExpression, lt, mode, flags)
return
}
p.unaryExpression(f, lhs, lt, exprLValue, flags)
p.w(" = ")
p.assignmentExpression(f, n.AssignmentExpression, lt, mode, flags)
}
case opBitfield:
bf := lt.BitField()
p.w("%sSetBitFieldPtr%d%s(", p.task.crt, bf.BitFieldBlockWidth(), p.bfHelperType(lt))
p.unaryExpression(f, lhs, lt, exprAddrOf, flags)
p.w(", ")
p.assignmentExpression(f, n.AssignmentExpression, lt, exprValue, flags)
p.w(", %d, %#x)", bf.BitFieldOffset(), bf.Mask())
case opUnion:
p.unaryExpression(f, lhs, lt, exprLValue, flags)
p.w(" = ")
p.assignmentExpression(f, n.AssignmentExpression, lt, exprValue, flags)
default:
panic(todo("", n.Position(), k))
}
f.condInitPrefix = sv
case cc.AssignmentExpressionMul: // UnaryExpression "*=" AssignmentExpression
p.assignOp(f, n, t, mode, "*", "Mul", flags)
case cc.AssignmentExpressionDiv: // UnaryExpression "/=" AssignmentExpression
p.assignOp(f, n, t, mode, "/", "Div", flags)
case cc.AssignmentExpressionMod: // UnaryExpression "%=" AssignmentExpression
p.assignOp(f, n, t, mode, "%", "Mod", flags)
case cc.AssignmentExpressionAdd: // UnaryExpression "+=" AssignmentExpression
p.assignOp(f, n, t, mode, "+", "Add", flags)
case cc.AssignmentExpressionSub: // UnaryExpression "-=" AssignmentExpression
p.assignOp(f, n, t, mode, "-", "Sub", flags)
case cc.AssignmentExpressionLsh: // UnaryExpression "<<=" AssignmentExpression
p.assignShiftOp(f, n, t, mode, "<<", "Shl", flags)
case cc.AssignmentExpressionRsh: // UnaryExpression ">>=" AssignmentExpression
p.assignShiftOp(f, n, t, mode, ">>", "Shr", flags)
case cc.AssignmentExpressionAnd: // UnaryExpression "&=" AssignmentExpression
p.assignOp(f, n, t, mode, "&", "And", flags)
case cc.AssignmentExpressionXor: // UnaryExpression "^=" AssignmentExpression
p.assignOp(f, n, t, mode, "^", "Xor", flags)
case cc.AssignmentExpressionOr: // UnaryExpression "|=" AssignmentExpression
p.assignOp(f, n, t, mode, "|", "Or", flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) setVolatileDeclarator(d *cc.Declarator, f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, flags flags) {
sz := d.Type().Size()
switch sz {
case 4, 8:
// ok
default:
p.err(d, "unsupported volatile declarator size: %v", sz)
return
}
if local := f.locals[d]; local != nil {
if local.isPinned {
p.w("%sAtomicStoreP%s(%s%s /* %s */, ", p.task.crt, p.helperType(n, d.Type()), f.bpName, nonZeroUintptr(local.off), local.name)
p.assignmentExpression(f, n, t, mode, flags)
p.w(")")
return
}
p.atomicStoreNamedAddr(n, d.Type(), local.name, n, f, mode, flags)
return
}
if tld := p.tlds[d]; tld != nil {
p.atomicStoreNamedAddr(n, d.Type(), tld.name, n, f, mode, flags)
return
}
if imp := p.imports[d.Name().String()]; imp != nil {
p.atomicStoreNamedAddr(n, d.Type(), fmt.Sprintf("%sX%s", imp.qualifier, d.Name()), n, f, mode, flags)
return
}
panic(todo("", n.Position(), d.Position(), d.Name()))
}
func (p *project) atomicStoreNamedAddr(n cc.Node, t cc.Type, nm string, expr *cc.AssignmentExpression, f *function, mode exprMode, flags flags) {
sz := t.Size()
switch sz {
case 4, 8:
// ok
default:
p.err(n, "unsupported volatile declarator size: %v", sz)
return
}
var ht string
switch {
case t.IsScalarType():
ht = p.helperType(n, t)
default:
p.err(n, "unsupported volatile declarator type: %v", t)
return
}
p.w("%sAtomicStore%s(&%s, %s(", p.task.crt, ht, nm, p.typ(n, t))
p.assignmentExpression(f, expr, t, mode, flags)
p.w("))")
}
func (p *project) atomicLoadNamedAddr(n cc.Node, t cc.Type, nm string) {
sz := t.Size()
switch sz {
case 4, 8:
// ok
default:
p.err(n, "unsupported volatile declarator size: %v", sz)
return
}
var ht string
switch {
case t.IsScalarType():
ht = p.helperType(n, t)
default:
p.err(n, "unsupported volatile declarator type: %v", t)
return
}
p.w("%sAtomicLoad%s(&%s)", p.task.crt, ht, nm)
}
func isRealType(op cc.Operand) bool {
switch op.Type().Kind() {
case cc.Float, cc.Double:
return true
default:
return false
}
}
func (p *project) bfHelperType(t cc.Type) string {
switch {
case t.IsSignedType():
return fmt.Sprintf("Int%d", t.Size()*8)
default:
return fmt.Sprintf("Uint%d", t.Size()*8)
}
}
func (p *project) helperType(n cc.Node, t cc.Type) string {
for t.IsAliasType() {
if t2 := t.Alias(); t2 != t { //TODO HDF5 H5O.c
t = t2
continue
}
break
}
switch t.Kind() {
case cc.Int128:
return "Int128"
case cc.UInt128:
return "Uint128"
}
s := p.typ(n, t)
return strings.ToUpper(s[:1]) + s[1:]
}
func (p *project) helperType2(n cc.Node, from, to cc.Type) string {
if from.Kind() == to.Kind() {
return fmt.Sprintf("%s%s", p.task.crt, p.helperType(n, from))
}
return fmt.Sprintf("%s%sFrom%s", p.task.crt, p.helperType(n, to), p.helperType(n, from))
}
func (p *project) conditionalExpression(f *function, n *cc.ConditionalExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.conditionalExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.conditionalExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.conditionalExpressionAddrOf(f, n, t, mode, flags)
case exprBool:
p.conditionalExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.conditionalExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.conditionalExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.conditionalExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.conditionalExpressionSelect(f, n, t, mode, flags)
case exprCondReturn:
p.conditionalExpressionReturn(f, n, t, mode, flags)
case exprCondInit:
p.conditionalExpressionInit(f, n, t, mode, flags)
case exprDecay:
p.conditionalExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) conditionalExpressionDecay(f *function, n *cc.ConditionalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ConditionalExpressionLOr: // LogicalOrExpression
p.logicalOrExpression(f, n.LogicalOrExpression, t, mode, flags)
case cc.ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression
t = t.Decay()
p.w(" func() %s { if ", p.typ(n, t))
p.logicalOrExpression(f, n.LogicalOrExpression, n.LogicalOrExpression.Operand.Type(), exprBool, flags)
p.w(" { return ")
switch n.Expression.Operand.Type().Kind() {
case cc.Array:
p.expression(f, n.Expression, t, exprDecay, flags)
case cc.Ptr:
panic(todo("", n.Expression.Position(), n.Expression.Operand.Type()))
default:
panic(todo("", n.Expression.Position(), n.Expression.Operand.Type()))
}
p.w("}; return ")
switch n.ConditionalExpression.Operand.Type().Kind() {
case cc.Array:
p.conditionalExpression(f, n.ConditionalExpression, t, exprDecay, flags)
default:
p.conditionalExpression(f, n.ConditionalExpression, t, exprValue, flags)
}
p.w("}()")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) conditionalExpressionInit(f *function, n *cc.ConditionalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ConditionalExpressionLOr: // LogicalOrExpression
f.condInitPrefix()
p.logicalOrExpression(f, n.LogicalOrExpression, t, exprValue, flags)
case cc.ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression
t = t.Decay()
p.w("if ")
p.logicalOrExpression(f, n.LogicalOrExpression, n.LogicalOrExpression.Operand.Type(), exprBool, flags)
p.w(" {")
p.expression(f, n.Expression, t, mode, flags)
p.w("} else { ")
p.conditionalExpression(f, n.ConditionalExpression, t, mode, flags)
p.w("}")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) conditionalExpressionReturn(f *function, n *cc.ConditionalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ConditionalExpressionLOr: // LogicalOrExpression
p.w("return ")
p.logicalOrExpression(f, n.LogicalOrExpression, t, exprValue, flags)
case cc.ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression
t = t.Decay()
p.w("if ")
p.logicalOrExpression(f, n.LogicalOrExpression, n.LogicalOrExpression.Operand.Type(), exprBool, flags)
p.w(" {")
p.expression(f, n.Expression, t, mode, flags)
p.w("}; ")
p.conditionalExpression(f, n.ConditionalExpression, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) conditionalExpressionSelect(f *function, n *cc.ConditionalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ConditionalExpressionLOr: // LogicalOrExpression
p.logicalOrExpression(f, n.LogicalOrExpression, t, mode, flags)
case cc.ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) conditionalExpressionFunc(f *function, n *cc.ConditionalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ConditionalExpressionLOr: // LogicalOrExpression
p.logicalOrExpression(f, n.LogicalOrExpression, t, mode, flags)
case cc.ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression
switch ot := n.Operand.Type(); ot.Kind() {
case cc.Function:
if t.Kind() != cc.Function {
panic(todo("", n.Position()))
}
default:
panic(todo("", ot.Kind()))
}
p.w(" func() ")
p.functionSignature(n, f, t, "")
p.w("{ if ")
p.logicalOrExpression(f, n.LogicalOrExpression, n.LogicalOrExpression.Operand.Type(), exprBool, flags)
p.w(" { return ")
switch d := n.Expression.Declarator(); {
case d != nil:
p.declaratorDefault(n, d)
default:
panic(todo("", n.Position()))
}
p.w("}; return ")
switch d := n.ConditionalExpression.Declarator(); {
case d != nil:
p.declaratorDefault(n, d)
default:
panic(todo("", n.Position()))
}
p.w("}()")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) conditionalExpressionPSelect(f *function, n *cc.ConditionalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ConditionalExpressionLOr: // LogicalOrExpression
p.logicalOrExpression(f, n.LogicalOrExpression, t, mode, flags)
case cc.ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression
p.w("(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type().Elem()))
p.conditionalExpression(f, n, t, exprValue, flags)
p.w("))")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) conditionalExpressionLValue(f *function, n *cc.ConditionalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ConditionalExpressionLOr: // LogicalOrExpression
p.logicalOrExpression(f, n.LogicalOrExpression, t, mode, flags)
case cc.ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) conditionalExpressionBool(f *function, n *cc.ConditionalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ConditionalExpressionLOr: // LogicalOrExpression
p.logicalOrExpression(f, n.LogicalOrExpression, t, mode, flags)
case cc.ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression
p.w("(")
defer p.w(")")
defer p.w(" != 0 ")
p.conditionalExpression(f, n, t, exprValue, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) conditionalExpressionAddrOf(f *function, n *cc.ConditionalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ConditionalExpressionLOr: // LogicalOrExpression
p.logicalOrExpression(f, n.LogicalOrExpression, t, mode, flags)
case cc.ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression
t = t.Decay()
p.w(" func() %s { if ", p.typ(n, t))
p.logicalOrExpression(f, n.LogicalOrExpression, n.LogicalOrExpression.Operand.Type(), exprBool, flags)
p.w(" { return ")
p.expression(f, n.Expression, t, exprValue, flags)
p.w("}; return ")
p.conditionalExpression(f, n.ConditionalExpression, t, exprValue, flags)
p.w("}()")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) conditionalExpressionVoid(f *function, n *cc.ConditionalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ConditionalExpressionLOr: // LogicalOrExpression
p.logicalOrExpression(f, n.LogicalOrExpression, t, mode, flags)
case cc.ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression
switch {
case n.Expression.IsSideEffectsFree:
p.w("if !(")
p.logicalOrExpression(f, n.LogicalOrExpression, n.LogicalOrExpression.Operand.Type(), exprBool, flags)
p.w(") {")
p.conditionalExpression(f, n.ConditionalExpression, n.ConditionalExpression.Operand.Type(), mode, flags)
p.w("}")
default:
p.w("if ")
p.logicalOrExpression(f, n.LogicalOrExpression, n.LogicalOrExpression.Operand.Type(), exprBool, flags)
p.w(" {")
p.expression(f, n.Expression, n.Expression.Operand.Type(), mode, flags)
p.w("} else {")
p.conditionalExpression(f, n.ConditionalExpression, n.ConditionalExpression.Operand.Type(), mode, flags)
p.w("}")
}
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) conditionalExpressionValue(f *function, n *cc.ConditionalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ConditionalExpressionLOr: // LogicalOrExpression
p.logicalOrExpression(f, n.LogicalOrExpression, t, exprValue, flags)
case cc.ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression
t = t.Decay()
p.w(" func() %s { if ", p.typ(n, t))
p.logicalOrExpression(f, n.LogicalOrExpression, n.LogicalOrExpression.Operand.Type(), exprBool, flags)
p.w(" { return ")
p.expression(f, n.Expression, t, exprValue, flags)
p.w("}; return ")
p.conditionalExpression(f, n.ConditionalExpression, t, exprValue, flags)
p.w("}()")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalOrExpression(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.logicalOrExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.logicalOrExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.logicalOrExpressionAddrOf(f, n, t, mode, flags)
case exprBool:
p.logicalOrExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.logicalOrExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.logicalOrExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.logicalOrExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.logicalOrExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.logicalOrExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) logicalOrExpressionDecay(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalOrExpressionLAnd: // LogicalAndExpression
p.logicalAndExpression(f, n.LogicalAndExpression, t, mode, flags)
case cc.LogicalOrExpressionLOr: // LogicalOrExpression "||" LogicalAndExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalOrExpressionSelect(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalOrExpressionLAnd: // LogicalAndExpression
p.logicalAndExpression(f, n.LogicalAndExpression, t, mode, flags)
case cc.LogicalOrExpressionLOr: // LogicalOrExpression "||" LogicalAndExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalOrExpressionFunc(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalOrExpressionLAnd: // LogicalAndExpression
p.logicalAndExpression(f, n.LogicalAndExpression, t, mode, flags)
case cc.LogicalOrExpressionLOr: // LogicalOrExpression "||" LogicalAndExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalOrExpressionPSelect(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalOrExpressionLAnd: // LogicalAndExpression
p.logicalAndExpression(f, n.LogicalAndExpression, t, mode, flags)
case cc.LogicalOrExpressionLOr: // LogicalOrExpression "||" LogicalAndExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalOrExpressionLValue(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalOrExpressionLAnd: // LogicalAndExpression
p.logicalAndExpression(f, n.LogicalAndExpression, t, mode, flags)
case cc.LogicalOrExpressionLOr: // LogicalOrExpression "||" LogicalAndExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalOrExpressionBool(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalOrExpressionLAnd: // LogicalAndExpression
p.logicalAndExpression(f, n.LogicalAndExpression, t, mode, flags)
case cc.LogicalOrExpressionLOr: // LogicalOrExpression "||" LogicalAndExpression
p.binaryLogicalOrExpression(f, n, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalOrExpressionAddrOf(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalOrExpressionLAnd: // LogicalAndExpression
p.logicalAndExpression(f, n.LogicalAndExpression, t, mode, flags)
case cc.LogicalOrExpressionLOr: // LogicalOrExpression "||" LogicalAndExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalOrExpressionVoid(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalOrExpressionLAnd: // LogicalAndExpression
p.logicalAndExpression(f, n.LogicalAndExpression, t, mode, flags)
case cc.LogicalOrExpressionLOr: // LogicalOrExpression "||" LogicalAndExpression
p.w("_ = ")
p.logicalOrExpression(f, n, n.Operand.Type(), exprValue, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalOrExpressionValue(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalOrExpressionLAnd: // LogicalAndExpression
p.logicalAndExpression(f, n.LogicalAndExpression, t, mode, flags)
case cc.LogicalOrExpressionLOr: // LogicalOrExpression "||" LogicalAndExpression
p.binaryLogicalOrExpression(f, n, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) binaryLogicalOrExpression(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.binaryLogicalOrExpressionValue(f, n, t, mode, flags)
case exprBool:
p.binaryLogicalOrExpressionBool(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) binaryLogicalOrExpressionBool(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
defer p.w("%s", p.booleanBinaryExpression(n, n.Operand, n.Operand.Type(), &mode, flags))
p.logicalOrExpression(f, n.LogicalOrExpression, n.LogicalOrExpression.Operand.Type(), exprBool, flags)
p.w(" ||%s", tidyComment(" ", &n.Token))
p.logicalAndExpression(f, n.LogicalAndExpression, n.LogicalAndExpression.Operand.Type(), exprBool, flags)
}
func (p *project) binaryLogicalOrExpressionValue(f *function, n *cc.LogicalOrExpression, t cc.Type, mode exprMode, flags flags) {
defer p.w("%s", p.booleanBinaryExpression(n, n.Operand, t, &mode, flags))
p.logicalOrExpression(f, n.LogicalOrExpression, n.LogicalOrExpression.Operand.Type(), exprBool, flags)
p.w(" ||%s", tidyComment(" ", &n.Token))
p.logicalAndExpression(f, n.LogicalAndExpression, n.LogicalAndExpression.Operand.Type(), exprBool, flags)
}
func (p *project) booleanBinaryExpression(n cc.Node, from cc.Operand, to cc.Type, mode *exprMode, flags flags) (r string) {
p.w("(")
r = ")"
switch *mode {
case exprBool:
*mode = exprValue
default:
r = p.convert(n, from, to, flags) + r
p.w("%sBool32(", p.task.crt)
r = ")" + r
}
return r
}
func (p *project) logicalAndExpression(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.logicalAndExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.logicalAndExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.logicalAndExpressionAddrOf(f, n, t, mode, flags)
case exprBool:
p.logicalAndExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.logicalAndExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.logicalAndExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.logicalAndExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.logicalAndExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.logicalAndExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) logicalAndExpressionDecay(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalAndExpressionOr: // InclusiveOrExpression
p.inclusiveOrExpression(f, n.InclusiveOrExpression, t, mode, flags)
case cc.LogicalAndExpressionLAnd: // LogicalAndExpression "&&" InclusiveOrExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalAndExpressionSelect(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalAndExpressionOr: // InclusiveOrExpression
p.inclusiveOrExpression(f, n.InclusiveOrExpression, t, mode, flags)
case cc.LogicalAndExpressionLAnd: // LogicalAndExpression "&&" InclusiveOrExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalAndExpressionFunc(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalAndExpressionOr: // InclusiveOrExpression
p.inclusiveOrExpression(f, n.InclusiveOrExpression, t, mode, flags)
case cc.LogicalAndExpressionLAnd: // LogicalAndExpression "&&" InclusiveOrExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalAndExpressionPSelect(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalAndExpressionOr: // InclusiveOrExpression
p.inclusiveOrExpression(f, n.InclusiveOrExpression, t, mode, flags)
case cc.LogicalAndExpressionLAnd: // LogicalAndExpression "&&" InclusiveOrExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalAndExpressionLValue(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalAndExpressionOr: // InclusiveOrExpression
p.inclusiveOrExpression(f, n.InclusiveOrExpression, t, mode, flags)
case cc.LogicalAndExpressionLAnd: // LogicalAndExpression "&&" InclusiveOrExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalAndExpressionBool(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalAndExpressionOr: // InclusiveOrExpression
p.inclusiveOrExpression(f, n.InclusiveOrExpression, t, mode, flags)
case cc.LogicalAndExpressionLAnd: // LogicalAndExpression "&&" InclusiveOrExpression
p.binaryLogicalAndExpression(f, n, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalAndExpressionAddrOf(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalAndExpressionOr: // InclusiveOrExpression
p.inclusiveOrExpression(f, n.InclusiveOrExpression, t, mode, flags)
case cc.LogicalAndExpressionLAnd: // LogicalAndExpression "&&" InclusiveOrExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalAndExpressionVoid(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalAndExpressionOr: // InclusiveOrExpression
p.inclusiveOrExpression(f, n.InclusiveOrExpression, t, mode, flags)
case cc.LogicalAndExpressionLAnd: // LogicalAndExpression "&&" InclusiveOrExpression
p.binaryLogicalAndExpressionValue(f, n, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) logicalAndExpressionValue(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.LogicalAndExpressionOr: // InclusiveOrExpression
p.inclusiveOrExpression(f, n.InclusiveOrExpression, t, mode, flags)
case cc.LogicalAndExpressionLAnd: // LogicalAndExpression "&&" InclusiveOrExpression
p.binaryLogicalAndExpression(f, n, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) binaryLogicalAndExpression(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprBool:
p.binaryLogicalAndExpressionBool(f, n, t, mode, flags)
case exprValue:
p.binaryLogicalAndExpressionValue(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) binaryLogicalAndExpressionValue(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
defer p.w("%s", p.booleanBinaryExpression(n, n.Operand, t, &mode, flags))
p.logicalAndExpression(f, n.LogicalAndExpression, n.LogicalAndExpression.Operand.Type(), exprBool, flags)
p.w(" &&%s", tidyComment(" ", &n.Token))
p.inclusiveOrExpression(f, n.InclusiveOrExpression, n.InclusiveOrExpression.Operand.Type(), exprBool, flags)
}
func (p *project) binaryLogicalAndExpressionBool(f *function, n *cc.LogicalAndExpression, t cc.Type, mode exprMode, flags flags) {
defer p.w("%s", p.booleanBinaryExpression(n, n.Operand, t, &mode, flags))
p.logicalAndExpression(f, n.LogicalAndExpression, n.LogicalAndExpression.Operand.Type(), exprBool, flags)
p.w(" &&%s", tidyComment(" ", &n.Token))
p.inclusiveOrExpression(f, n.InclusiveOrExpression, n.InclusiveOrExpression.Operand.Type(), exprBool, flags)
}
func (p *project) inclusiveOrExpression(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.inclusiveOrExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.inclusiveOrExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.inclusiveOrExpressionAddrof(f, n, t, mode, flags)
case exprBool:
p.inclusiveOrExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.inclusiveOrExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.inclusiveOrExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.inclusiveOrExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.inclusiveOrExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.inclusiveOrExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) inclusiveOrExpressionDecay(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.InclusiveOrExpressionXor: // ExclusiveOrExpression
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, t, mode, flags)
case cc.InclusiveOrExpressionOr: // InclusiveOrExpression '|' ExclusiveOrExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) inclusiveOrExpressionSelect(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.InclusiveOrExpressionXor: // ExclusiveOrExpression
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, t, mode, flags)
case cc.InclusiveOrExpressionOr: // InclusiveOrExpression '|' ExclusiveOrExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) inclusiveOrExpressionFunc(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.InclusiveOrExpressionXor: // ExclusiveOrExpression
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, t, mode, flags)
case cc.InclusiveOrExpressionOr: // InclusiveOrExpression '|' ExclusiveOrExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) inclusiveOrExpressionPSelect(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.InclusiveOrExpressionXor: // ExclusiveOrExpression
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, t, mode, flags)
case cc.InclusiveOrExpressionOr: // InclusiveOrExpression '|' ExclusiveOrExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) inclusiveOrExpressionLValue(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.InclusiveOrExpressionXor: // ExclusiveOrExpression
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, t, mode, flags)
case cc.InclusiveOrExpressionOr: // InclusiveOrExpression '|' ExclusiveOrExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) inclusiveOrExpressionBool(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.InclusiveOrExpressionXor: // ExclusiveOrExpression
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, t, mode, flags)
case cc.InclusiveOrExpressionOr: // InclusiveOrExpression '|' ExclusiveOrExpression
p.binaryInclusiveOrExpression(f, n, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) inclusiveOrExpressionAddrof(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.InclusiveOrExpressionXor: // ExclusiveOrExpression
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, t, mode, flags)
case cc.InclusiveOrExpressionOr: // InclusiveOrExpression '|' ExclusiveOrExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) inclusiveOrExpressionVoid(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.InclusiveOrExpressionXor: // ExclusiveOrExpression
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, t, mode, flags)
case cc.InclusiveOrExpressionOr: // InclusiveOrExpression '|' ExclusiveOrExpression
p.w("_ = ")
p.inclusiveOrExpression(f, n, n.Operand.Type(), exprValue, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) inclusiveOrExpressionValue(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.InclusiveOrExpressionXor: // ExclusiveOrExpression
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, t, mode, flags)
case cc.InclusiveOrExpressionOr: // InclusiveOrExpression '|' ExclusiveOrExpression
p.binaryInclusiveOrExpression(f, n, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) binaryInclusiveOrExpression(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
// InclusiveOrExpression '|' ExclusiveOrExpression
switch mode {
case exprBool:
p.binaryInclusiveOrExpressionBool(f, n, t, mode, flags)
case exprValue:
p.binaryInclusiveOrExpressionValue(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) binaryInclusiveOrExpressionValue(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
// InclusiveOrExpression '|' ExclusiveOrExpression
lt := n.InclusiveOrExpression.Operand.Type()
rt := n.ExclusiveOrExpression.Operand.Type()
switch lk, rk := lt.Kind(), rt.Kind(); {
case
lk == cc.UInt128 || rk == cc.UInt128,
lk == cc.Int128 || rk == cc.Int128:
p.binaryOrExpressionUint128(f, n, t, mode, flags)
return
}
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, t, &mode, flags))
switch {
case orOverflows(n.InclusiveOrExpression.Operand, n.ExclusiveOrExpression.Operand, n.Promote()):
p.inclusiveOrExpression(f, n.InclusiveOrExpression, n.Promote(), exprValue, flags)
p.w(" |%s", tidyComment(" ", &n.Token))
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, n.Promote(), exprValue, flags|fForceRuntimeConv)
default:
p.inclusiveOrExpression(f, n.InclusiveOrExpression, n.Promote(), exprValue, flags)
p.w(" |%s", tidyComment(" ", &n.Token))
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, n.Promote(), exprValue, flags)
}
}
func (p *project) binaryOrExpressionUint128(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
// InclusiveOrExpression '|' ExclusiveOrExpression
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, t, &mode, flags))
p.inclusiveOrExpression(f, n.InclusiveOrExpression, n.Promote(), exprValue, flags)
p.w(".Or(")
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, n.Promote(), exprValue, flags)
p.w(")")
}
func (p *project) binaryInclusiveOrExpressionBool(f *function, n *cc.InclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, t, &mode, flags))
switch {
case orOverflows(n.InclusiveOrExpression.Operand, n.ExclusiveOrExpression.Operand, n.Promote()):
p.inclusiveOrExpression(f, n.InclusiveOrExpression, n.Promote(), exprValue, flags)
p.w(" |%s", tidyComment(" ", &n.Token))
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, n.Promote(), exprValue, flags|fForceRuntimeConv)
default:
p.inclusiveOrExpression(f, n.InclusiveOrExpression, n.Promote(), exprValue, flags)
p.w(" |%s", tidyComment(" ", &n.Token))
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, n.Promote(), exprValue, flags)
}
}
func orOverflows(lo, ro cc.Operand, promote cc.Type) bool {
a, b, ok := getIntOperands(lo, ro)
if !ok {
return false
}
return overflows(a.Or(a, b), promote)
}
func (p *project) artithmeticBinaryExpression(n cc.Node, from cc.Operand, to cc.Type, mode *exprMode, flags flags) (r string) {
p.w("(")
r = ")"
switch *mode {
case exprBool:
p.w("(")
r = ") != 0" + r
*mode = exprValue
default:
switch fk, tk := from.Type().Kind(), to.Kind(); {
case fk != tk && fk == cc.Int128:
return fmt.Sprintf(".%s()%s", p.helperType(n, to), r)
case fk != tk && fk == cc.UInt128:
return fmt.Sprintf(".%s()%s", p.helperType(n, to), r)
default:
r = p.convert(n, from, to, flags) + r
}
}
return r
}
func (p *project) exclusiveOrExpression(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.exclusiveOrExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.exclusiveOrExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.exclusiveOrExpressionAddrOf(f, n, t, mode, flags)
case exprBool:
p.exclusiveOrExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.exclusiveOrExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.exclusiveOrExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.exclusiveOrExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.exclusiveOrExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.exclusiveOrExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) exclusiveOrExpressionDecay(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExclusiveOrExpressionAnd: // AndExpression
p.andExpression(f, n.AndExpression, t, mode, flags)
case cc.ExclusiveOrExpressionXor: // ExclusiveOrExpression '^' AndExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) exclusiveOrExpressionSelect(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExclusiveOrExpressionAnd: // AndExpression
p.andExpression(f, n.AndExpression, t, mode, flags)
case cc.ExclusiveOrExpressionXor: // ExclusiveOrExpression '^' AndExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) exclusiveOrExpressionFunc(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExclusiveOrExpressionAnd: // AndExpression
p.andExpression(f, n.AndExpression, t, mode, flags)
case cc.ExclusiveOrExpressionXor: // ExclusiveOrExpression '^' AndExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) exclusiveOrExpressionPSelect(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExclusiveOrExpressionAnd: // AndExpression
p.andExpression(f, n.AndExpression, t, mode, flags)
case cc.ExclusiveOrExpressionXor: // ExclusiveOrExpression '^' AndExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) exclusiveOrExpressionLValue(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExclusiveOrExpressionAnd: // AndExpression
p.andExpression(f, n.AndExpression, t, mode, flags)
case cc.ExclusiveOrExpressionXor: // ExclusiveOrExpression '^' AndExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) exclusiveOrExpressionBool(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExclusiveOrExpressionAnd: // AndExpression
p.andExpression(f, n.AndExpression, t, mode, flags)
case cc.ExclusiveOrExpressionXor: // ExclusiveOrExpression '^' AndExpression
p.binaryExclusiveOrExpression(f, n, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) exclusiveOrExpressionAddrOf(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExclusiveOrExpressionAnd: // AndExpression
p.andExpression(f, n.AndExpression, t, mode, flags)
case cc.ExclusiveOrExpressionXor: // ExclusiveOrExpression '^' AndExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) exclusiveOrExpressionVoid(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExclusiveOrExpressionAnd: // AndExpression
p.andExpression(f, n.AndExpression, t, mode, flags)
case cc.ExclusiveOrExpressionXor: // ExclusiveOrExpression '^' AndExpression
p.w("_ = ")
p.exclusiveOrExpression(f, n, n.Operand.Type(), exprValue, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) exclusiveOrExpressionValue(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ExclusiveOrExpressionAnd: // AndExpression
p.andExpression(f, n.AndExpression, t, mode, flags)
case cc.ExclusiveOrExpressionXor: // ExclusiveOrExpression '^' AndExpression
p.binaryExclusiveOrExpression(f, n, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) binaryExclusiveOrExpression(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
// ExclusiveOrExpression '^' AndExpression
switch mode {
case exprValue, exprBool:
p.binaryExclusiveOrExpressionValue(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) binaryExclusiveOrExpressionValue(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
// ExclusiveOrExpression '^' AndExpression
lt := n.ExclusiveOrExpression.Operand.Type()
rt := n.AndExpression.Operand.Type()
switch lk, rk := lt.Kind(), rt.Kind(); {
case
lk == cc.UInt128 || rk == cc.UInt128,
lk == cc.Int128 || rk == cc.Int128:
p.binaryExclusiveOrExpressionUint128(f, n, t, mode, flags)
return
}
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, t, &mode, flags))
switch {
case xorOverflows(n.ExclusiveOrExpression.Operand, n.AndExpression.Operand, n.Promote()):
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, n.Promote(), exprValue, flags)
p.w(" ^%s", tidyComment(" ", &n.Token))
p.andExpression(f, n.AndExpression, n.Promote(), exprValue, flags|fForceRuntimeConv)
default:
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, n.Promote(), exprValue, flags)
p.w(" ^%s", tidyComment(" ", &n.Token))
p.andExpression(f, n.AndExpression, n.Promote(), exprValue, flags)
}
}
func (p *project) binaryExclusiveOrExpressionUint128(f *function, n *cc.ExclusiveOrExpression, t cc.Type, mode exprMode, flags flags) {
// ExclusiveOrExpression '^' AndExpression
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, t, &mode, flags))
p.exclusiveOrExpression(f, n.ExclusiveOrExpression, n.Promote(), exprValue, flags)
p.w(".Xor(")
p.andExpression(f, n.AndExpression, n.Promote(), exprValue, flags)
p.w(")")
}
func xorOverflows(lo, ro cc.Operand, promote cc.Type) bool {
a, b, ok := getIntOperands(lo, ro)
if !ok {
return false
}
return !lo.Type().IsSignedType() && a.Sign() == 0 ||
!ro.Type().IsSignedType() && b.Sign() == 0 ||
overflows(a.Xor(a, b), promote)
}
func (p *project) andExpression(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.andExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.andExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.andExpressionAddrof(f, n, t, mode, flags)
case exprBool:
p.andExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.andExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.andExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.andExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.andExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.andExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) andExpressionDecay(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AndExpressionEq: // EqualityExpression
p.equalityExpression(f, n.EqualityExpression, t, mode, flags)
case cc.AndExpressionAnd: // AndExpression '&' EqualityExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) andExpressionSelect(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AndExpressionEq: // EqualityExpression
p.equalityExpression(f, n.EqualityExpression, t, mode, flags)
case cc.AndExpressionAnd: // AndExpression '&' EqualityExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) andExpressionFunc(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AndExpressionEq: // EqualityExpression
p.equalityExpression(f, n.EqualityExpression, t, mode, flags)
case cc.AndExpressionAnd: // AndExpression '&' EqualityExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) andExpressionPSelect(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AndExpressionEq: // EqualityExpression
p.equalityExpression(f, n.EqualityExpression, t, mode, flags)
case cc.AndExpressionAnd: // AndExpression '&' EqualityExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) andExpressionLValue(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AndExpressionEq: // EqualityExpression
p.equalityExpression(f, n.EqualityExpression, t, mode, flags)
case cc.AndExpressionAnd: // AndExpression '&' EqualityExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) andExpressionBool(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AndExpressionEq: // EqualityExpression
p.equalityExpression(f, n.EqualityExpression, t, mode, flags)
case cc.AndExpressionAnd: // AndExpression '&' EqualityExpression
p.binaryAndExpression(f, n, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) andExpressionAddrof(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AndExpressionEq: // EqualityExpression
p.equalityExpression(f, n.EqualityExpression, t, mode, flags)
case cc.AndExpressionAnd: // AndExpression '&' EqualityExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) andExpressionVoid(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AndExpressionEq: // EqualityExpression
p.equalityExpression(f, n.EqualityExpression, t, mode, flags)
case cc.AndExpressionAnd: // AndExpression '&' EqualityExpression
p.w("_ = ")
p.andExpression(f, n, n.Operand.Type(), exprValue, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) andExpressionValue(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AndExpressionEq: // EqualityExpression
p.equalityExpression(f, n.EqualityExpression, t, mode, flags)
case cc.AndExpressionAnd: // AndExpression '&' EqualityExpression
p.binaryAndExpression(f, n, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) binaryAndExpression(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
// AndExpression '&' EqualityExpression
switch mode {
case exprValue:
p.binaryAndExpressionValue(f, n, t, mode, flags)
case exprBool:
p.binaryAndExpressionBool(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) binaryAndExpressionBool(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, n.Operand.Type(), &mode, flags))
switch {
case andOverflows(n.AndExpression.Operand, n.EqualityExpression.Operand, n.Promote()):
p.andExpression(f, n.AndExpression, n.Promote(), exprValue, flags)
p.w(" &%s", tidyComment(" ", &n.Token))
p.equalityExpression(f, n.EqualityExpression, n.Promote(), exprValue, flags|fForceRuntimeConv)
default:
p.andExpression(f, n.AndExpression, n.Promote(), exprValue, flags)
p.w(" &%s", tidyComment(" ", &n.Token))
p.equalityExpression(f, n.EqualityExpression, n.Promote(), exprValue, flags)
}
}
func (p *project) binaryAndExpressionValue(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
// AndExpression '&' EqualityExpression
lt := n.AndExpression.Operand.Type()
rt := n.EqualityExpression.Operand.Type()
switch lk, rk := lt.Kind(), rt.Kind(); {
case
lk == cc.UInt128 || rk == cc.UInt128,
lk == cc.Int128 || rk == cc.Int128:
p.binaryAndExpressionUint128(f, n, t, mode, flags)
return
}
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, t, &mode, flags))
switch {
case andOverflows(n.AndExpression.Operand, n.EqualityExpression.Operand, n.Promote()):
p.andExpression(f, n.AndExpression, n.Promote(), exprValue, flags)
p.w(" &%s", tidyComment(" ", &n.Token))
p.equalityExpression(f, n.EqualityExpression, n.Promote(), exprValue, flags|fForceRuntimeConv)
default:
p.andExpression(f, n.AndExpression, n.Promote(), exprValue, flags)
p.w(" &%s", tidyComment(" ", &n.Token))
p.equalityExpression(f, n.EqualityExpression, n.Promote(), exprValue, flags)
}
}
func (p *project) binaryAndExpressionUint128(f *function, n *cc.AndExpression, t cc.Type, mode exprMode, flags flags) {
// AndExpression '&' EqualityExpression
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, t, &mode, flags))
p.andExpression(f, n.AndExpression, n.Promote(), exprValue, flags)
p.w(".And(")
p.equalityExpression(f, n.EqualityExpression, n.Promote(), exprValue, flags)
p.w(")")
}
func andOverflows(lo, ro cc.Operand, promote cc.Type) bool {
a, b, ok := getIntOperands(lo, ro)
if !ok {
return false
}
return overflows(a.And(a, b), promote)
}
func (p *project) equalityExpression(f *function, n *cc.EqualityExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.equalityExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.equalityExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.equalityExpressionAddrOf(f, n, t, mode, flags)
case exprBool:
p.equalityExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.equalityExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.equalityExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.equalityExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.equalityExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.equalityExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) equalityExpressionDecay(f *function, n *cc.EqualityExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.EqualityExpressionRel: // RelationalExpression
p.relationalExpression(f, n.RelationalExpression, t, mode, flags)
case cc.EqualityExpressionEq: // EqualityExpression "==" RelationalExpression
panic(todo("", p.pos(n)))
case cc.EqualityExpressionNeq: // EqualityExpression "!=" RelationalExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) equalityExpressionSelect(f *function, n *cc.EqualityExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.EqualityExpressionRel: // RelationalExpression
p.relationalExpression(f, n.RelationalExpression, t, mode, flags)
case cc.EqualityExpressionEq: // EqualityExpression "==" RelationalExpression
panic(todo("", p.pos(n)))
case cc.EqualityExpressionNeq: // EqualityExpression "!=" RelationalExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) equalityExpressionFunc(f *function, n *cc.EqualityExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.EqualityExpressionRel: // RelationalExpression
p.relationalExpression(f, n.RelationalExpression, t, mode, flags)
case cc.EqualityExpressionEq: // EqualityExpression "==" RelationalExpression
panic(todo("", p.pos(n)))
case cc.EqualityExpressionNeq: // EqualityExpression "!=" RelationalExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) equalityExpressionPSelect(f *function, n *cc.EqualityExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.EqualityExpressionRel: // RelationalExpression
p.relationalExpression(f, n.RelationalExpression, t, mode, flags)
case cc.EqualityExpressionEq: // EqualityExpression "==" RelationalExpression
panic(todo("", p.pos(n)))
case cc.EqualityExpressionNeq: // EqualityExpression "!=" RelationalExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) equalityExpressionLValue(f *function, n *cc.EqualityExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.EqualityExpressionRel: // RelationalExpression
p.relationalExpression(f, n.RelationalExpression, t, mode, flags)
case cc.EqualityExpressionEq: // EqualityExpression "==" RelationalExpression
panic(todo("", p.pos(n)))
case cc.EqualityExpressionNeq: // EqualityExpression "!=" RelationalExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) equalityExpressionBool(f *function, n *cc.EqualityExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.EqualityExpressionRel: // RelationalExpression
p.relationalExpression(f, n.RelationalExpression, t, mode, flags)
case cc.EqualityExpressionEq: // EqualityExpression "==" RelationalExpression
p.binaryEqualityExpression(f, n, " == ", t, mode, flags)
case cc.EqualityExpressionNeq: // EqualityExpression "!=" RelationalExpression
p.binaryEqualityExpression(f, n, " != ", t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) equalityExpressionAddrOf(f *function, n *cc.EqualityExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.EqualityExpressionRel: // RelationalExpression
p.relationalExpression(f, n.RelationalExpression, t, mode, flags)
case cc.EqualityExpressionEq: // EqualityExpression "==" RelationalExpression
panic(todo("", p.pos(n)))
case cc.EqualityExpressionNeq: // EqualityExpression "!=" RelationalExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) equalityExpressionVoid(f *function, n *cc.EqualityExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.EqualityExpressionRel: // RelationalExpression
p.relationalExpression(f, n.RelationalExpression, t, mode, flags)
default:
// case cc.EqualityExpressionEq: // EqualityExpression "==" RelationalExpression
// case cc.EqualityExpressionNeq: // EqualityExpression "!=" RelationalExpression
p.w("_ = ")
p.equalityExpression(f, n, n.Operand.Type(), exprValue, flags)
}
}
func (p *project) equalityExpressionValue(f *function, n *cc.EqualityExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.EqualityExpressionRel: // RelationalExpression
p.relationalExpression(f, n.RelationalExpression, t, mode, flags)
case cc.EqualityExpressionEq: // EqualityExpression "==" RelationalExpression
p.binaryEqualityExpression(f, n, " == ", t, mode, flags)
case cc.EqualityExpressionNeq: // EqualityExpression "!=" RelationalExpression
p.binaryEqualityExpression(f, n, " != ", t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) binaryEqualityExpression(f *function, n *cc.EqualityExpression, oper string, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.binaryEqualityExpressionValue(f, n, oper, t, mode, flags)
case exprBool:
p.binaryEqualityExpressionBool(f, n, oper, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) binaryEqualityExpressionBool(f *function, n *cc.EqualityExpression, oper string, t cc.Type, mode exprMode, flags flags) {
defer p.w("%s", p.booleanBinaryExpression(n, n.Operand, t, &mode, flags))
p.equalityExpression(f, n.EqualityExpression, n.Promote(), exprValue, flags)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.relationalExpression(f, n.RelationalExpression, n.Promote(), exprValue, flags)
}
func (p *project) binaryEqualityExpressionValue(f *function, n *cc.EqualityExpression, oper string, t cc.Type, mode exprMode, flags flags) {
defer p.w("%s", p.booleanBinaryExpression(n, n.Operand, t, &mode, flags))
p.equalityExpression(f, n.EqualityExpression, n.Promote(), exprValue, flags)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.relationalExpression(f, n.RelationalExpression, n.Promote(), exprValue, flags)
}
func (p *project) relationalExpression(f *function, n *cc.RelationalExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.relationalExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.relationalExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.relationalExpressionAddrOf(f, n, t, mode, flags)
case exprBool:
p.relationalExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.relationalExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.relationalExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.relationalExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.relationalExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.relationalExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) relationalExpressionDecay(f *function, n *cc.RelationalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.RelationalExpressionShift: // ShiftExpression
p.shiftExpression(f, n.ShiftExpression, t, mode, flags)
case cc.RelationalExpressionLt: // RelationalExpression '<' ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionGt: // RelationalExpression '>' ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionLeq: // RelationalExpression "<=" ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionGeq: // RelationalExpression ">=" ShiftExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) relationalExpressionSelect(f *function, n *cc.RelationalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.RelationalExpressionShift: // ShiftExpression
p.shiftExpression(f, n.ShiftExpression, t, mode, flags)
case cc.RelationalExpressionLt: // RelationalExpression '<' ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionGt: // RelationalExpression '>' ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionLeq: // RelationalExpression "<=" ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionGeq: // RelationalExpression ">=" ShiftExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) relationalExpressionFunc(f *function, n *cc.RelationalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.RelationalExpressionShift: // ShiftExpression
p.shiftExpression(f, n.ShiftExpression, t, mode, flags)
case cc.RelationalExpressionLt: // RelationalExpression '<' ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionGt: // RelationalExpression '>' ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionLeq: // RelationalExpression "<=" ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionGeq: // RelationalExpression ">=" ShiftExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) relationalExpressionPSelect(f *function, n *cc.RelationalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.RelationalExpressionShift: // ShiftExpression
p.shiftExpression(f, n.ShiftExpression, t, mode, flags)
case cc.RelationalExpressionLt: // RelationalExpression '<' ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionGt: // RelationalExpression '>' ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionLeq: // RelationalExpression "<=" ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionGeq: // RelationalExpression ">=" ShiftExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) relationalExpressionLValue(f *function, n *cc.RelationalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.RelationalExpressionShift: // ShiftExpression
p.shiftExpression(f, n.ShiftExpression, t, mode, flags)
case cc.RelationalExpressionLt: // RelationalExpression '<' ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionGt: // RelationalExpression '>' ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionLeq: // RelationalExpression "<=" ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionGeq: // RelationalExpression ">=" ShiftExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) relationalExpressionBool(f *function, n *cc.RelationalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.RelationalExpressionShift: // ShiftExpression
p.shiftExpression(f, n.ShiftExpression, t, mode, flags)
case cc.RelationalExpressionLt: // RelationalExpression '<' ShiftExpression
p.binaryRelationalExpression(f, n, " < ", t, mode, flags)
case cc.RelationalExpressionGt: // RelationalExpression '>' ShiftExpression
p.binaryRelationalExpression(f, n, " > ", t, mode, flags)
case cc.RelationalExpressionLeq: // RelationalExpression "<=" ShiftExpression
p.binaryRelationalExpression(f, n, " <= ", t, mode, flags)
case cc.RelationalExpressionGeq: // RelationalExpression ">=" ShiftExpression
p.binaryRelationalExpression(f, n, " >= ", t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) relationalExpressionAddrOf(f *function, n *cc.RelationalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.RelationalExpressionShift: // ShiftExpression
p.shiftExpression(f, n.ShiftExpression, t, mode, flags)
case cc.RelationalExpressionLt: // RelationalExpression '<' ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionGt: // RelationalExpression '>' ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionLeq: // RelationalExpression "<=" ShiftExpression
panic(todo("", p.pos(n)))
case cc.RelationalExpressionGeq: // RelationalExpression ">=" ShiftExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) relationalExpressionVoid(f *function, n *cc.RelationalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.RelationalExpressionShift: // ShiftExpression
p.shiftExpression(f, n.ShiftExpression, t, mode, flags)
default:
// case cc.RelationalExpressionLt: // RelationalExpression '<' ShiftExpression
// case cc.RelationalExpressionGt: // RelationalExpression '>' ShiftExpression
// case cc.RelationalExpressionLeq: // RelationalExpression "<=" ShiftExpression
// case cc.RelationalExpressionGeq: // RelationalExpression ">=" ShiftExpression
p.w("_ = ")
p.relationalExpression(f, n, n.Operand.Type(), exprValue, flags)
}
}
func (p *project) relationalExpressionValue(f *function, n *cc.RelationalExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.RelationalExpressionShift: // ShiftExpression
p.shiftExpression(f, n.ShiftExpression, t, mode, flags)
case cc.RelationalExpressionLt: // RelationalExpression '<' ShiftExpression
p.binaryRelationalExpression(f, n, " < ", t, mode, flags)
case cc.RelationalExpressionGt: // RelationalExpression '>' ShiftExpression
p.binaryRelationalExpression(f, n, " > ", t, mode, flags)
case cc.RelationalExpressionLeq: // RelationalExpression "<=" ShiftExpression
p.binaryRelationalExpression(f, n, " <= ", t, mode, flags)
case cc.RelationalExpressionGeq: // RelationalExpression ">=" ShiftExpression
p.binaryRelationalExpression(f, n, " >= ", t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) binaryRelationalExpression(f *function, n *cc.RelationalExpression, oper string, t cc.Type, mode exprMode, flags flags) {
// RelationalExpression "<=" ShiftExpression
lt := n.RelationalExpression.Operand.Type()
rt := n.ShiftExpression.Operand.Type()
switch lk, rk := lt.Kind(), rt.Kind(); {
case
lk == cc.UInt128 || rk == cc.UInt128,
lk == cc.Int128 || rk == cc.Int128:
p.binaryRelationalExpressionInt128(f, n, oper, t, mode, flags)
return
}
defer p.w("%s", p.booleanBinaryExpression(n, n.Operand, t, &mode, flags))
p.relationalExpression(f, n.RelationalExpression, n.Promote(), exprValue, flags)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.shiftExpression(f, n.ShiftExpression, n.Promote(), exprValue, flags)
}
func (p *project) binaryRelationalExpressionInt128(f *function, n *cc.RelationalExpression, oper string, t cc.Type, mode exprMode, flags flags) {
// RelationalExpression "<=" ShiftExpression
defer p.w("%s", p.booleanBinaryExpression(n, n.Operand, t, &mode, flags))
p.relationalExpression(f, n.RelationalExpression, n.Promote(), exprValue, flags)
p.w(".Cmp(")
p.shiftExpression(f, n.ShiftExpression, n.Promote(), exprValue, flags)
p.w(") %s 0", oper)
}
func (p *project) shiftExpression(f *function, n *cc.ShiftExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.shiftExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.shiftExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.shiftExpressionAddrOf(f, n, t, mode, flags)
case exprBool:
p.shiftExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.shiftExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.shiftExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.shiftExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.shiftExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.shiftExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) shiftExpressionDecay(f *function, n *cc.ShiftExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ShiftExpressionAdd: // AdditiveExpression
p.additiveExpression(f, n.AdditiveExpression, t, mode, flags)
case cc.ShiftExpressionLsh: // ShiftExpression "<<" AdditiveExpression
panic(todo("", p.pos(n)))
case cc.ShiftExpressionRsh: // ShiftExpression ">>" AdditiveExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) shiftExpressionSelect(f *function, n *cc.ShiftExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ShiftExpressionAdd: // AdditiveExpression
p.additiveExpression(f, n.AdditiveExpression, t, mode, flags)
case cc.ShiftExpressionLsh: // ShiftExpression "<<" AdditiveExpression
panic(todo("", p.pos(n)))
case cc.ShiftExpressionRsh: // ShiftExpression ">>" AdditiveExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) shiftExpressionFunc(f *function, n *cc.ShiftExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ShiftExpressionAdd: // AdditiveExpression
p.additiveExpression(f, n.AdditiveExpression, t, mode, flags)
case cc.ShiftExpressionLsh: // ShiftExpression "<<" AdditiveExpression
panic(todo("", p.pos(n)))
case cc.ShiftExpressionRsh: // ShiftExpression ">>" AdditiveExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) shiftExpressionPSelect(f *function, n *cc.ShiftExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ShiftExpressionAdd: // AdditiveExpression
p.additiveExpression(f, n.AdditiveExpression, t, mode, flags)
case cc.ShiftExpressionLsh: // ShiftExpression "<<" AdditiveExpression
panic(todo("", p.pos(n)))
case cc.ShiftExpressionRsh: // ShiftExpression ">>" AdditiveExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) shiftExpressionLValue(f *function, n *cc.ShiftExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ShiftExpressionAdd: // AdditiveExpression
p.additiveExpression(f, n.AdditiveExpression, t, mode, flags)
case cc.ShiftExpressionLsh: // ShiftExpression "<<" AdditiveExpression
panic(todo("", p.pos(n)))
case cc.ShiftExpressionRsh: // ShiftExpression ">>" AdditiveExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) shiftExpressionBool(f *function, n *cc.ShiftExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ShiftExpressionAdd: // AdditiveExpression
p.additiveExpression(f, n.AdditiveExpression, t, mode, flags)
case cc.ShiftExpressionLsh: // ShiftExpression "<<" AdditiveExpression
p.binaryShiftExpression(f, n, "<<", t, mode, flags)
case cc.ShiftExpressionRsh: // ShiftExpression ">>" AdditiveExpression
p.binaryShiftExpression(f, n, ">>", t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) shiftExpressionAddrOf(f *function, n *cc.ShiftExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ShiftExpressionAdd: // AdditiveExpression
p.additiveExpression(f, n.AdditiveExpression, t, mode, flags)
case cc.ShiftExpressionLsh: // ShiftExpression "<<" AdditiveExpression
panic(todo("", p.pos(n)))
case cc.ShiftExpressionRsh: // ShiftExpression ">>" AdditiveExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) shiftExpressionVoid(f *function, n *cc.ShiftExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ShiftExpressionAdd: // AdditiveExpression
p.additiveExpression(f, n.AdditiveExpression, t, mode, flags)
case cc.ShiftExpressionLsh: // ShiftExpression "<<" AdditiveExpression
panic(todo("", p.pos(n)))
case cc.ShiftExpressionRsh: // ShiftExpression ">>" AdditiveExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) shiftExpressionValue(f *function, n *cc.ShiftExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.ShiftExpressionAdd: // AdditiveExpression
p.additiveExpression(f, n.AdditiveExpression, t, mode, flags)
case cc.ShiftExpressionLsh: // ShiftExpression "<<" AdditiveExpression
p.binaryShiftExpression(f, n, "<<", t, mode, flags)
case cc.ShiftExpressionRsh: // ShiftExpression ">>" AdditiveExpression
p.binaryShiftExpression(f, n, ">>", t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) binaryShiftExpression(f *function, n *cc.ShiftExpression, oper string, t cc.Type, mode exprMode, flags flags) {
// ShiftExpression "<<" AdditiveExpression
switch mode {
case exprValue:
p.binaryShiftExpressionValue(f, n, oper, t, mode, flags)
case exprBool:
p.binaryShiftExpressionBool(f, n, oper, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) todo(n cc.Node, t cc.Type) {
p.w("func() %s { panic(`%v: TODO (%v)`)}()", p.typ(n, t), n.Position(), origin(2))
}
func (p *project) binaryShiftExpressionBool(f *function, n *cc.ShiftExpression, oper string, t cc.Type, mode exprMode, flags flags) {
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, n.Operand.Type(), &mode, flags))
switch {
case n.ShiftExpression.Operand.Type().IsBitFieldType():
p.w("(")
p.shiftExpression(f, n.ShiftExpression, n.Operand.Type(), exprValue, flags)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
p.w(")&%#x", bfValueMask(n.ShiftExpression.Operand.Type().BitField()))
case shiftOverflows(n, n.ShiftExpression.Operand, n.AdditiveExpression.Operand, oper, n.Operand.Type()):
p.shiftExpression(f, n.ShiftExpression, n.Operand.Type(), exprValue, flags|fForceRuntimeConv)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
case isConstInteger(n.ShiftExpression.Operand):
s := p.convertNil(n, n.Operand.Type(), 0)
p.shiftExpression(f, n.ShiftExpression, n.Operand.Type(), exprValue, flags)
p.w("%s %s%s", s, oper, tidyComment(" ", &n.Token))
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
default:
p.shiftExpression(f, n.ShiftExpression, n.Operand.Type(), exprValue, flags)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
}
}
func shiftOp(s string) string {
switch s {
case "<<":
return "Shl"
case ">>":
return "Shr"
default:
panic(todo("%q", s))
}
}
func bfValueMask(bf cc.Field) uint64 {
return uint64(1)<<bf.BitFieldWidth() - 1
}
func (p *project) binaryShiftExpressionValue(f *function, n *cc.ShiftExpression, oper string, t cc.Type, mode exprMode, flags flags) {
// ShiftExpression "<<" AdditiveExpression
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, t, &mode, flags))
switch k := n.ShiftExpression.Operand.Type().Kind(); {
case k == cc.Int128, k == cc.UInt128:
p.w("(")
p.shiftExpression(f, n.ShiftExpression, n.Operand.Type(), exprValue, flags)
p.w(").%s(", shiftOp(oper))
p.additiveExpression(f, n.AdditiveExpression, p.intType, exprValue, flags)
p.w(")")
case n.ShiftExpression.Operand.Type().IsBitFieldType():
p.w("(")
p.shiftExpression(f, n.ShiftExpression, n.Operand.Type(), exprValue, flags)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
p.w(")&%#x", bfValueMask(n.ShiftExpression.Operand.Type().BitField()))
case shiftOverflows(n, n.ShiftExpression.Operand, n.AdditiveExpression.Operand, oper, n.Operand.Type()):
p.shiftExpression(f, n.ShiftExpression, n.Operand.Type(), exprValue, flags|fForceRuntimeConv)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
case isConstInteger(n.ShiftExpression.Operand):
s := p.convertNil(n, n.Operand.Type(), 0)
p.shiftExpression(f, n.ShiftExpression, n.Operand.Type(), exprValue, flags)
p.w("%s %s%s", s, oper, tidyComment(" ", &n.Token))
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
default:
p.shiftExpression(f, n.ShiftExpression, n.Operand.Type(), exprValue, flags)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
}
}
func shiftOverflows(n cc.Node, lo, ro cc.Operand, oper string, result cc.Type) bool {
a, b, ok := getIntOperands(lo, ro)
if !ok {
return false
}
if !b.IsUint64() {
return true
}
bits := b.Uint64()
if bits > mathutil.MaxUint {
return true
}
switch oper {
case "<<":
return overflows(a.Lsh(a, uint(bits)), result)
case ">>":
return overflows(a.Rsh(a, uint(bits)), result)
default:
panic(todo("", pos(n)))
}
}
func (p *project) additiveExpression(f *function, n *cc.AdditiveExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.additiveExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.additiveExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.additiveExpressionAddrOf(f, n, t, mode, flags)
case exprBool:
p.additiveExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.additiveExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.additiveExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.additiveExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.additiveExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.additiveExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) additiveExpressionDecay(f *function, n *cc.AdditiveExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AdditiveExpressionMul: // MultiplicativeExpression
p.multiplicativeExpression(f, n.MultiplicativeExpression, t, mode, flags)
case cc.AdditiveExpressionAdd: // AdditiveExpression '+' MultiplicativeExpression
panic(todo("", p.pos(n)))
case cc.AdditiveExpressionSub: // AdditiveExpression '-' MultiplicativeExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) additiveExpressionSelect(f *function, n *cc.AdditiveExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AdditiveExpressionMul: // MultiplicativeExpression
p.multiplicativeExpression(f, n.MultiplicativeExpression, t, mode, flags)
case cc.AdditiveExpressionAdd: // AdditiveExpression '+' MultiplicativeExpression
panic(todo("", p.pos(n)))
case cc.AdditiveExpressionSub: // AdditiveExpression '-' MultiplicativeExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) additiveExpressionFunc(f *function, n *cc.AdditiveExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AdditiveExpressionMul: // MultiplicativeExpression
p.multiplicativeExpression(f, n.MultiplicativeExpression, t, mode, flags)
case cc.AdditiveExpressionAdd: // AdditiveExpression '+' MultiplicativeExpression
panic(todo("", p.pos(n)))
case cc.AdditiveExpressionSub: // AdditiveExpression '-' MultiplicativeExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) additiveExpressionPSelect(f *function, n *cc.AdditiveExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AdditiveExpressionMul: // MultiplicativeExpression
p.multiplicativeExpression(f, n.MultiplicativeExpression, t, mode, flags)
case cc.AdditiveExpressionAdd: // AdditiveExpression '+' MultiplicativeExpression
p.w("(*%s)(unsafe.Pointer(", p.typ(n, t.Elem()))
p.additiveExpression(f, n, t, exprValue, flags)
p.w("))")
case cc.AdditiveExpressionSub: // AdditiveExpression '-' MultiplicativeExpression
p.w("(*%s)(unsafe.Pointer(", p.typ(n, t.Elem()))
p.additiveExpression(f, n, t, exprValue, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) additiveExpressionLValue(f *function, n *cc.AdditiveExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AdditiveExpressionMul: // MultiplicativeExpression
p.multiplicativeExpression(f, n.MultiplicativeExpression, t, mode, flags)
case cc.AdditiveExpressionAdd: // AdditiveExpression '+' MultiplicativeExpression
panic(todo("", p.pos(n)))
case cc.AdditiveExpressionSub: // AdditiveExpression '-' MultiplicativeExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) additiveExpressionBool(f *function, n *cc.AdditiveExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AdditiveExpressionMul: // MultiplicativeExpression
p.multiplicativeExpression(f, n.MultiplicativeExpression, t, mode, flags)
case cc.AdditiveExpressionAdd: // AdditiveExpression '+' MultiplicativeExpression
p.binaryAdditiveExpression(f, n, "+", t, mode, flags)
case cc.AdditiveExpressionSub: // AdditiveExpression '-' MultiplicativeExpression
p.binaryAdditiveExpression(f, n, "-", t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) additiveExpressionAddrOf(f *function, n *cc.AdditiveExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AdditiveExpressionMul: // MultiplicativeExpression
p.multiplicativeExpression(f, n.MultiplicativeExpression, t, mode, flags)
case cc.AdditiveExpressionAdd: // AdditiveExpression '+' MultiplicativeExpression
panic(todo("", p.pos(n)))
case cc.AdditiveExpressionSub: // AdditiveExpression '-' MultiplicativeExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) additiveExpressionVoid(f *function, n *cc.AdditiveExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AdditiveExpressionMul: // MultiplicativeExpression
p.multiplicativeExpression(f, n.MultiplicativeExpression, t, mode, flags)
case
cc.AdditiveExpressionAdd, // AdditiveExpression '+' MultiplicativeExpression
cc.AdditiveExpressionSub: // AdditiveExpression '-' MultiplicativeExpression
p.w("_ = ")
p.additiveExpression(f, n, n.Operand.Type(), exprValue, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) additiveExpressionValue(f *function, n *cc.AdditiveExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.AdditiveExpressionMul: // MultiplicativeExpression
p.multiplicativeExpression(f, n.MultiplicativeExpression, t, mode, flags)
case cc.AdditiveExpressionAdd: // AdditiveExpression '+' MultiplicativeExpression
p.binaryAdditiveExpression(f, n, "+", t, mode, flags)
case cc.AdditiveExpressionSub: // AdditiveExpression '-' MultiplicativeExpression
p.binaryAdditiveExpression(f, n, "-", t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) binaryAdditiveExpression(f *function, n *cc.AdditiveExpression, oper string, t cc.Type, mode exprMode, flags flags) {
// AdditiveExpression '+' MultiplicativeExpression
switch mode {
case exprValue:
p.binaryAdditiveExpressionValue(f, n, oper, t, mode, flags)
case exprBool:
p.binaryAdditiveExpressionBool(f, n, oper, t, mode, flags)
default:
panic(todo("", mode))
}
}
func (p *project) binaryAdditiveExpressionBool(f *function, n *cc.AdditiveExpression, oper string, t cc.Type, mode exprMode, flags flags) {
// AdditiveExpression '+' MultiplicativeExpression
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, n.Operand.Type(), &mode, flags))
lo := n.AdditiveExpression.Operand
ro := n.MultiplicativeExpression.Operand
lt := lo.Type()
rt := ro.Type()
switch {
case lt.Kind() == cc.Ptr && rt.Kind() == cc.Ptr && oper == "-":
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.multiplicativeExpression(f, n.MultiplicativeExpression, n.Promote(), exprValue, flags)
case lt.IsArithmeticType() && rt.IsArithmeticType(): // x +- y
defer p.w("%s", p.bitFieldPatch2(n, lo, ro, n.Promote())) //TODO bit field big endian
switch {
case intAddOverflows(n, lo, ro, oper, n.Promote()): // i +- j
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.multiplicativeExpression(f, n.MultiplicativeExpression, n.Promote(), exprValue, flags|fForceRuntimeConv)
default:
var s string
if isRealType(n.Operand) && n.Operand.Value() != nil {
s = p.convertNil(n, n.Promote(), flags)
}
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
p.w("%s %s%s", s, oper, tidyComment(" ", &n.Token))
p.multiplicativeExpression(f, n.MultiplicativeExpression, n.Promote(), exprValue, flags)
}
default:
panic(todo("", n.Position(), lt, rt, oper))
}
}
func (p *project) binaryAdditiveExpressionValue(f *function, n *cc.AdditiveExpression, oper string, t cc.Type, mode exprMode, flags flags) {
// AdditiveExpression '+' MultiplicativeExpression
lt := n.AdditiveExpression.Operand.Type()
rt := n.MultiplicativeExpression.Operand.Type()
switch lk, rk := lt.Kind(), rt.Kind(); {
case
lk == cc.UInt128 || rk == cc.UInt128,
lk == cc.Int128 || rk == cc.Int128:
p.binaryAdditiveExpressionUint128(f, n, oper, t, mode, flags)
return
}
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, t, &mode, flags))
lo := n.AdditiveExpression.Operand
ro := n.MultiplicativeExpression.Operand
switch {
case lt.IsArithmeticType() && rt.IsArithmeticType(): // x +- y
defer p.w("%s", p.bitFieldPatch2(n, lo, ro, n.Promote())) //TODO bit field big endian
switch {
case intAddOverflows(n, lo, ro, oper, n.Promote()): // i +- j
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.multiplicativeExpression(f, n.MultiplicativeExpression, n.Promote(), exprValue, flags|fForceRuntimeConv)
default:
var s string
if isRealType(n.Operand) && n.Operand.Value() != nil {
s = p.convertNil(n, n.Promote(), flags)
}
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
p.w("%s %s%s", s, oper, tidyComment(" ", &n.Token))
p.multiplicativeExpression(f, n.MultiplicativeExpression, n.Promote(), exprValue, flags)
}
case lt.Kind() == cc.Ptr && rt.IsIntegerType(): // p +- i
p.additiveExpression(f, n.AdditiveExpression, lt, exprValue, flags)
p.w(" %s%s uintptr(", oper, tidyComment(" ", &n.Token))
p.multiplicativeExpression(f, n.MultiplicativeExpression, rt, exprValue, flags)
p.w(")")
if sz := lt.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
case lt.Kind() == cc.Array && rt.IsIntegerType(): // p +- i
p.additiveExpression(f, n.AdditiveExpression, lt, exprDecay, flags)
p.w(" %s%s uintptr(", oper, tidyComment(" ", &n.Token))
p.multiplicativeExpression(f, n.MultiplicativeExpression, rt, exprValue, flags)
p.w(")")
if sz := lt.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
case lt.IsIntegerType() && rt.Kind() == cc.Ptr: // i +- p
p.w("uintptr(")
p.additiveExpression(f, n.AdditiveExpression, lt, exprValue, flags)
p.w(")")
if sz := rt.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
p.w(" %s%s ", oper, tidyComment(" ", &n.Token))
p.multiplicativeExpression(f, n.MultiplicativeExpression, rt, exprValue, flags)
case lt.IsIntegerType() && rt.Kind() == cc.Array: // i +- p
panic(todo("", p.pos(n)))
case lt.Kind() == cc.Ptr && rt.Kind() == cc.Ptr && oper == "-": // p - q
p.w("(")
p.additiveExpression(f, n.AdditiveExpression, n.Operand.Type(), exprValue, flags)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.multiplicativeExpression(f, n.MultiplicativeExpression, n.Operand.Type(), exprValue, flags)
p.w(")/%d", lt.Elem().Size())
case lt.Kind() == cc.Ptr && rt.Kind() == cc.Array && oper == "-": // p - q
defer p.w("%s", p.convertType(n, nil, n.Operand.Type(), 0))
p.w("(")
p.additiveExpression(f, n.AdditiveExpression, lt, exprValue, flags)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.multiplicativeExpression(f, n.MultiplicativeExpression, rt.Decay(), exprDecay, flags)
p.w(")/%d", lt.Elem().Size())
case lt.Kind() == cc.Array && rt.Kind() == cc.Ptr && oper == "-": // p - q
panic(todo("", p.pos(n)))
case lt.Kind() == cc.Array && rt.Kind() == cc.Array && oper == "-": // p - q
panic(todo("", p.pos(n)))
default:
panic(todo("", n.Position(), lt, rt, oper))
}
}
func (p *project) binaryAdditiveExpressionUint128(f *function, n *cc.AdditiveExpression, oper string, t cc.Type, mode exprMode, flags flags) {
// AdditiveExpression '+' MultiplicativeExpression
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, t, &mode, flags))
p.additiveExpression(f, n.AdditiveExpression, n.Promote(), exprValue, flags)
switch oper {
case "+":
p.w(".Add(")
case "-":
p.w(".Sub(")
default:
panic(todo("%q", oper))
}
p.multiplicativeExpression(f, n.MultiplicativeExpression, n.Promote(), exprValue, flags)
p.w(")")
}
func (p *project) bitFieldPatch2(n cc.Node, a, b cc.Operand, promote cc.Type) string {
//TODO bit field big endian
var m uint64
var w int
switch {
case a.Type().IsBitFieldType():
bf := a.Type().BitField()
w = bf.BitFieldWidth()
m = bf.Mask() >> bf.BitFieldOffset()
if b.Type().IsBitFieldType() {
bf = b.Type().BitField()
w2 := bf.BitFieldWidth()
if w2 != w {
panic(todo("", p.pos(n)))
}
}
case b.Type().IsBitFieldType():
bf := b.Type().BitField()
w = bf.BitFieldWidth()
m = bf.Mask() >> bf.BitFieldOffset()
default:
return ""
}
p.w("((")
switch {
case promote.IsSignedType():
n := int(promote.Size())*8 - w
var s string
switch promote.Size() {
case 4:
s = fmt.Sprintf(")&%#x", int32(m))
default:
s = fmt.Sprintf(")&%#x", m)
}
if n != 0 {
s += fmt.Sprintf("<<%d>>%[1]d", n)
}
return ")" + s
default:
return fmt.Sprintf(")&%#x)", m)
}
}
func intAddOverflows(n cc.Node, lo, ro cc.Operand, oper string, promote cc.Type) bool {
a, b, ok := getIntOperands(lo, ro)
if !ok {
return false
}
switch oper {
case "+":
return overflows(a.Add(a, b), promote)
case "-":
return overflows(a.Sub(a, b), promote)
default:
panic(todo("", pos(n)))
}
}
func getIntOperands(a, b cc.Operand) (x, y *big.Int, ok bool) {
switch n := a.Value().(type) {
case cc.Int64Value:
x = big.NewInt(int64(n))
case cc.Uint64Value:
x = big.NewInt(0).SetUint64(uint64(n))
default:
return nil, nil, false
}
switch n := b.Value().(type) {
case cc.Int64Value:
return x, big.NewInt(int64(n)), true
case cc.Uint64Value:
return x, big.NewInt(0).SetUint64(uint64(n)), true
default:
return nil, nil, false
}
}
func overflows(n *big.Int, promote cc.Type) bool {
switch k := promote.Kind(); {
case k == cc.Int128, k == cc.UInt128:
return false
case isSigned(promote):
switch promote.Size() {
case 4:
return n.Cmp(minInt32) < 0 || n.Cmp(maxInt32) > 0
case 8:
return n.Cmp(minInt64) < 0 || n.Cmp(maxInt64) > 0
}
default:
switch promote.Size() {
case 4:
return n.Sign() < 0 || n.Cmp(maxUint32) > 0
case 8:
return n.Sign() < 0 || n.Cmp(maxUint64) > 0
}
}
panic(todo("", promote.Size(), promote))
}
func (p *project) multiplicativeExpression(f *function, n *cc.MultiplicativeExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprValue:
p.multiplicativeExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.multiplicativeExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.multiplicativeExpressionAddrOf(f, n, t, mode, flags)
case exprBool:
p.multiplicativeExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.multiplicativeExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.multiplicativeExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.multiplicativeExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.multiplicativeExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.multiplicativeExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) multiplicativeExpressionDecay(f *function, n *cc.MultiplicativeExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.MultiplicativeExpressionCast: // CastExpression
p.castExpression(f, n.CastExpression, t, mode, flags)
case cc.MultiplicativeExpressionMul: // MultiplicativeExpression '*' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionDiv: // MultiplicativeExpression '/' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionMod: // MultiplicativeExpression '%' CastExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) multiplicativeExpressionSelect(f *function, n *cc.MultiplicativeExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.MultiplicativeExpressionCast: // CastExpression
p.castExpression(f, n.CastExpression, t, mode, flags)
case cc.MultiplicativeExpressionMul: // MultiplicativeExpression '*' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionDiv: // MultiplicativeExpression '/' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionMod: // MultiplicativeExpression '%' CastExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) multiplicativeExpressionFunc(f *function, n *cc.MultiplicativeExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.MultiplicativeExpressionCast: // CastExpression
p.castExpression(f, n.CastExpression, t, mode, flags)
case cc.MultiplicativeExpressionMul: // MultiplicativeExpression '*' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionDiv: // MultiplicativeExpression '/' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionMod: // MultiplicativeExpression '%' CastExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) multiplicativeExpressionPSelect(f *function, n *cc.MultiplicativeExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.MultiplicativeExpressionCast: // CastExpression
p.castExpression(f, n.CastExpression, t, mode, flags)
case cc.MultiplicativeExpressionMul: // MultiplicativeExpression '*' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionDiv: // MultiplicativeExpression '/' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionMod: // MultiplicativeExpression '%' CastExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) multiplicativeExpressionLValue(f *function, n *cc.MultiplicativeExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.MultiplicativeExpressionCast: // CastExpression
p.castExpression(f, n.CastExpression, t, mode, flags)
case cc.MultiplicativeExpressionMul: // MultiplicativeExpression '*' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionDiv: // MultiplicativeExpression '/' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionMod: // MultiplicativeExpression '%' CastExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) multiplicativeExpressionBool(f *function, n *cc.MultiplicativeExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.MultiplicativeExpressionCast: // CastExpression
p.castExpression(f, n.CastExpression, t, mode, flags)
case
cc.MultiplicativeExpressionMul, // MultiplicativeExpression '*' CastExpression
cc.MultiplicativeExpressionDiv, // MultiplicativeExpression '/' CastExpression
cc.MultiplicativeExpressionMod: // MultiplicativeExpression '%' CastExpression
p.w("(")
defer p.w(")")
defer p.w(" != 0 ")
p.multiplicativeExpression(f, n, t, exprValue, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) multiplicativeExpressionAddrOf(f *function, n *cc.MultiplicativeExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.MultiplicativeExpressionCast: // CastExpression
p.castExpression(f, n.CastExpression, t, mode, flags)
case cc.MultiplicativeExpressionMul: // MultiplicativeExpression '*' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionDiv: // MultiplicativeExpression '/' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionMod: // MultiplicativeExpression '%' CastExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) multiplicativeExpressionVoid(f *function, n *cc.MultiplicativeExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.MultiplicativeExpressionCast: // CastExpression
p.castExpression(f, n.CastExpression, t, mode, flags)
case cc.MultiplicativeExpressionMul: // MultiplicativeExpression '*' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionDiv: // MultiplicativeExpression '/' CastExpression
panic(todo("", p.pos(n)))
case cc.MultiplicativeExpressionMod: // MultiplicativeExpression '%' CastExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) multiplicativeExpressionValue(f *function, n *cc.MultiplicativeExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.MultiplicativeExpressionCast: // CastExpression
p.castExpression(f, n.CastExpression, t, mode, flags)
case cc.MultiplicativeExpressionMul: // MultiplicativeExpression '*' CastExpression
p.binaryMultiplicativeExpression(f, n, "*", t, mode, flags)
case cc.MultiplicativeExpressionDiv: // MultiplicativeExpression '/' CastExpression
p.binaryMultiplicativeExpression(f, n, "/", t, mode, flags)
case cc.MultiplicativeExpressionMod: // MultiplicativeExpression '%' CastExpression
p.binaryMultiplicativeExpression(f, n, "%", t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) binaryMultiplicativeExpression(f *function, n *cc.MultiplicativeExpression, oper string, t cc.Type, mode exprMode, flags flags) {
// MultiplicativeExpression '*' CastExpression
switch mode {
case exprValue:
p.binaryMultiplicativeExpressionValue(f, n, oper, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) binaryMultiplicativeExpressionValue(f *function, n *cc.MultiplicativeExpression, oper string, t cc.Type, mode exprMode, flags flags) {
// MultiplicativeExpression '*' CastExpression
lt := n.MultiplicativeExpression.Operand.Type()
rt := n.CastExpression.Operand.Type()
switch lk, rk := lt.Kind(), rt.Kind(); {
case
lk == cc.UInt128 || rk == cc.UInt128,
lk == cc.Int128 || rk == cc.Int128:
p.binaryMultiplicativeExpressionUint128(f, n, oper, t, mode, flags)
return
}
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, t, &mode, flags))
switch {
case intMulOverflows(n, n.Operand, n.MultiplicativeExpression.Operand, n.CastExpression.Operand, oper, n.Promote()):
p.multiplicativeExpression(f, n.MultiplicativeExpression, n.Promote(), exprValue, flags|fForceRuntimeConv)
p.w(" %s%s", oper, tidyComment(" ", &n.Token))
p.castExpression(f, n.CastExpression, n.Promote(), exprValue, flags|fForceRuntimeConv)
default:
defer p.w("%s", p.bitFieldPatch2(n, n.MultiplicativeExpression.Operand, n.CastExpression.Operand, n.Promote())) //TODO bit field big endian
var s string
if isRealType(n.Operand) && n.Operand.Value() != nil {
s = p.convertNil(n, n.Promote(), flags)
}
p.multiplicativeExpression(f, n.MultiplicativeExpression, n.Promote(), exprValue, flags)
p.w("%s %s%s", s, oper, tidyComment(" ", &n.Token))
if (oper == "/" || oper == "%") && (isZeroReal(n.MultiplicativeExpression.Operand) || isZeroReal(n.CastExpression.Operand)) {
p.w("%s%sFrom%[2]s(", p.task.crt, p.helperType(n, n.Promote()))
defer p.w(")")
}
p.castExpression(f, n.CastExpression, n.Promote(), exprValue, flags)
}
}
func (p *project) binaryMultiplicativeExpressionUint128(f *function, n *cc.MultiplicativeExpression, oper string, t cc.Type, mode exprMode, flags flags) {
// MultiplicativeExpression '*' CastExpression
defer p.w("%s", p.artithmeticBinaryExpression(n, n.Operand, t, &mode, flags))
p.multiplicativeExpression(f, n.MultiplicativeExpression, n.Promote(), exprValue, flags)
switch oper {
case "*":
p.w(".Mul(")
case "/":
p.w(".Div(")
case "%":
p.w(".Mod(")
default:
panic(todo("%q", oper))
}
p.castExpression(f, n.CastExpression, n.Promote(), exprValue, flags)
p.w(")")
}
func isZeroReal(op cc.Operand) bool {
switch x := op.Value().(type) {
case cc.Float32Value:
return x == 0
case cc.Float64Value:
return x == 0
default:
return false
}
}
func intMulOverflows(n cc.Node, r, lo, ro cc.Operand, oper string, promote cc.Type) bool {
if (isReal(lo) && !isInf(lo) || isReal(ro) && !isInf(ro)) && isInf(r) {
return true
}
a, b, ok := getIntOperands(lo, ro)
if !ok {
return false
}
switch oper {
case "*":
return overflows(a.Mul(a, b), promote)
case "/":
if b.Sign() == 0 {
return true
}
return overflows(a.Div(a, b), promote)
case "%":
if b.Sign() == 0 {
return true
}
return overflows(a.Mod(a, b), promote)
default:
panic(todo("", pos(n)))
}
}
func isReal(op cc.Operand) bool {
switch op.Value().(type) {
case cc.Float32Value, cc.Float64Value:
return true
default:
return false
}
}
func isInf(op cc.Operand) bool {
switch x := op.Value().(type) {
case cc.Float32Value:
return math.IsInf(float64(x), 0)
case cc.Float64Value:
return math.IsInf(float64(x), 0)
default:
return false
}
}
func (p *project) castExpression(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
if n.Case == cc.CastExpressionCast {
if f != nil && n.CastExpression.Operand.Type().Kind() == cc.Ptr { // void *__ccgo_va_arg(__builtin_va_list ap);
sv := f.vaType
f.vaType = n.TypeName.Type()
defer func() { f.vaType = sv }()
}
}
switch mode {
case exprValue:
p.castExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.castExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.castExpressionAddrOf(f, n, t, mode, flags)
case exprBool:
p.castExpressionBool(f, n, t, mode, flags)
case exprLValue:
p.castExpressionLValue(f, n, t, mode, flags)
case exprPSelect:
p.castExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.castExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.castExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.castExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) castExpressionDecay(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.CastExpressionUnary: // UnaryExpression
p.unaryExpression(f, n.UnaryExpression, t, mode, flags)
case cc.CastExpressionCast: // '(' TypeName ')' CastExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) castExpressionSelect(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.CastExpressionUnary: // UnaryExpression
p.unaryExpression(f, n.UnaryExpression, t, mode, flags)
case cc.CastExpressionCast: // '(' TypeName ')' CastExpression
p.castExpression(f, n.CastExpression, n.TypeName.Type(), mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) castExpressionFunc(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.CastExpressionUnary: // UnaryExpression
p.unaryExpression(f, n.UnaryExpression, t, mode, flags)
case cc.CastExpressionCast: // '(' TypeName ')' CastExpression
ot := n.CastExpression.Operand.Type()
tn := n.TypeName.Type()
var ft cc.Type
switch tn.Kind() {
case cc.Ptr:
switch et := ot.Elem(); et.Kind() {
case cc.Function, cc.Void:
// ok
default:
panic(todo("", p.pos(n), et, et.Kind()))
}
default:
panic(todo("%v: %v, %v -> %v, %v -> %v, %v", p.pos(n), ot, ot.Kind(), tn, tn.Kind(), t, t.Kind()))
}
switch t.Kind() {
case cc.Ptr:
switch et := t.Elem(); et.Kind() {
case cc.Function:
ft = et
default:
panic(todo("", p.pos(n), et, et.Kind()))
}
default:
panic(todo("%v: %v, %v -> %v, %v -> %v, %v", p.pos(n), ot, ot.Kind(), tn, tn.Kind(), t, t.Kind()))
}
switch ot.Kind() {
case cc.Ptr:
switch et := ot.Elem(); et.Kind() {
case cc.Function, cc.Void:
p.w("(*(*")
p.functionSignature(n, f, ft, "")
p.w(")(unsafe.Pointer(")
p.castExpression(f, n.CastExpression, ot, exprAddrOf, flags)
p.w(")))")
default:
panic(todo("", p.pos(n), et, et.Kind()))
}
default:
panic(todo("%v: %v, %v -> %v, %v -> %v, %v", p.pos(n), ot, ot.Kind(), tn, tn.Kind(), t, t.Kind()))
}
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) castExpressionPSelect(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.CastExpressionUnary: // UnaryExpression
p.unaryExpression(f, n.UnaryExpression, t, mode, flags)
case cc.CastExpressionCast: // '(' TypeName ')' CastExpression
p.castExpression(f, n.CastExpression, n.TypeName.Type(), mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) castExpressionLValue(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.CastExpressionUnary: // UnaryExpression
p.unaryExpression(f, n.UnaryExpression, t, mode, flags)
case cc.CastExpressionCast: // '(' TypeName ')' CastExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) castExpressionBool(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.CastExpressionUnary: // UnaryExpression
p.unaryExpression(f, n.UnaryExpression, t, mode, flags)
case cc.CastExpressionCast: // '(' TypeName ')' CastExpression
p.w("(")
defer p.w(")")
defer p.w(" != 0 ")
p.castExpression(f, n, n.Operand.Type(), exprValue, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) castExpressionAddrOf(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.CastExpressionUnary: // UnaryExpression
p.unaryExpression(f, n.UnaryExpression, t, mode, flags)
case cc.CastExpressionCast: // '(' TypeName ')' CastExpression
p.castExpressionAddrOf(f, n.CastExpression, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) castExpressionVoid(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.CastExpressionUnary: // UnaryExpression
p.unaryExpression(f, n.UnaryExpression, t, mode, flags)
case cc.CastExpressionCast: // '(' TypeName ')' CastExpression
p.castExpression(f, n.CastExpression, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) castExpressionValue(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.CastExpressionUnary: // UnaryExpression
p.unaryExpression(f, n.UnaryExpression, t, mode, flags)
case cc.CastExpressionCast: // '(' TypeName ')' CastExpression
if f != nil && p.pass1 && n.TypeName.Type().IsIntegerType() && n.CastExpression.Operand.Type().Kind() == cc.Array {
if d := n.CastExpression.Declarator(); d != nil {
f.pin(n, d)
}
}
switch k := p.opKind(f, n.CastExpression, n.CastExpression.Operand.Type()); k {
case opNormal, opBitfield:
p.castExpressionValueNormal(f, n, t, mode, flags)
case opArray:
p.castExpressionValueArray(f, n, t, mode, flags)
case opFunction:
p.castExpressionValueFunction(f, n, t, mode, flags)
case opArrayParameter:
p.castExpressionValueNormal(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) castExpressionValueArrayParameter(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
// '(' TypeName ')' CastExpression
tn := n.TypeName.Type()
defer p.w("%s", p.convertType(n, tn, t, flags))
p.castExpression(f, n.CastExpression, tn, mode, flags)
}
func (p *project) castExpressionValueFunction(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
// '(' TypeName ')' CastExpression
op := n.CastExpression.Operand
tn := n.TypeName.Type()
switch {
case op.Type().Kind() == cc.Function:
switch {
case tn.Kind() == cc.Ptr && t.Kind() == cc.Ptr:
p.castExpression(f, n.CastExpression, op.Type(), exprValue, flags)
case tn.IsIntegerType():
p.w("%s(", p.typ(n, tn))
p.castExpression(f, n.CastExpression, op.Type(), exprValue, flags)
p.w(")")
default:
panic(todo("%v: tn %v expr %v", n.Position(), tn, op.Type()))
}
default:
panic(todo("%v: %v -> %v -> %v", p.pos(n), op.Type(), tn, t))
}
}
func (p *project) castExpressionValueArray(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
// '(' TypeName ')' CastExpression
tn := n.TypeName.Type()
switch {
case tn.IsScalarType():
defer p.w("%s", p.convertType(n, nil, t, flags))
p.castExpression(f, n.CastExpression, tn, exprDecay, flags)
default:
panic(todo("", p.pos(n)))
}
}
func (p *project) castExpressionValueNormal(f *function, n *cc.CastExpression, t cc.Type, mode exprMode, flags flags) {
// '(' TypeName ')' CastExpression
op := n.CastExpression.Operand
tn := n.TypeName.Type()
switch {
case op.Type().Kind() == cc.Ptr && tn.IsArithmeticType():
defer p.w("%s", p.convertType(n, nil, t, flags|fForceConv))
p.castExpression(f, n.CastExpression, op.Type(), mode, flags)
case tn.IsArithmeticType():
switch {
case (tn.Kind() == cc.Float || tn.Kind() == cc.Double) && op.Type().IsIntegerType() && op.Value() != nil && t.IsIntegerType():
panic(todo("", p.pos(n)))
case isNegativeInt(op) && isUnsigned(t):
defer p.w("%s", p.convertType(n, tn, t, flags|fForceConv))
p.castExpression(f, n.CastExpression, tn, exprValue, flags)
default:
defer p.w("%s", p.convertType(n, tn, t, flags))
p.castExpression(f, n.CastExpression, tn, exprValue, flags)
}
default:
switch tn.Kind() {
case cc.Ptr:
switch {
case t.Kind() == cc.Ptr && isNegativeInt(op):
p.w("%s(", p.helperType2(n, op.Type(), tn))
defer p.w(")")
p.castExpression(f, n.CastExpression, op.Type(), mode, flags)
default:
defer p.w("%s", p.convertType(n, tn, t, flags))
p.castExpression(f, n.CastExpression, tn, mode, flags)
}
case cc.Void:
p.castExpression(f, n.CastExpression, tn, exprVoid, flags)
default:
panic(todo("%s: %s %s -> %s %s -> %s %s", n.Position(), op.Type(), op.Type().Kind(), tn, tn.Kind(), t, t.Kind()))
}
}
}
func (p *project) unaryExpression(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprLValue:
p.unaryExpressionLValue(f, n, t, mode, flags)
case exprValue:
p.unaryExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.unaryExpressionVoid(f, n, t, mode, flags)
case exprAddrOf:
p.unaryExpressionAddrOf(f, n, t, mode, flags)
case exprBool:
p.unaryExpressionBool(f, n, t, mode, flags)
case exprPSelect:
p.unaryExpressionPSelect(f, n, t, mode, flags)
case exprFunc:
p.unaryExpressionFunc(f, n, t, mode, flags)
case exprSelect:
p.unaryExpressionSelect(f, n, t, mode, flags)
case exprDecay:
p.unaryExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) unaryExpressionDecay(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.UnaryExpressionPostfix: // PostfixExpression
p.postfixExpression(f, n.PostfixExpression, t, mode, flags)
case cc.UnaryExpressionInc: // "++" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionDec: // "--" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionAddrof: // '&' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionDeref: // '*' CastExpression
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprValue, flags)
case cc.UnaryExpressionPlus: // '+' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionMinus: // '-' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionCpl: // '~' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionNot: // '!' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionSizeofExpr: // "sizeof" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionSizeofType: // "sizeof" '(' TypeName ')'
panic(todo("", p.pos(n)))
case cc.UnaryExpressionLabelAddr: // "&&" IDENTIFIER
panic(todo("", p.pos(n)))
case cc.UnaryExpressionAlignofExpr: // "_Alignof" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionAlignofType: // "_Alignof" '(' TypeName ')'
panic(todo("", p.pos(n)))
case cc.UnaryExpressionImag: // "__imag__" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionReal: // "__real__" UnaryExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) unaryExpressionSelect(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.UnaryExpressionPostfix: // PostfixExpression
p.postfixExpression(f, n.PostfixExpression, t, mode, flags)
case cc.UnaryExpressionInc: // "++" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionDec: // "--" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionAddrof: // '&' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionDeref: // '*' CastExpression
ot := n.CastExpression.Operand.Type()
switch ot.Kind() {
case cc.Ptr:
switch et := ot.Elem(); et.Kind() {
case
cc.Struct,
cc.Union:
p.w("(*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprValue, flags)
p.w(")))")
default:
panic(todo("", p.pos(n), et, et.Kind()))
}
case cc.Array:
p.w("(*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprAddrOf, flags)
p.w(")))")
default:
panic(todo("", p.pos(n), ot, ot.Kind()))
}
case cc.UnaryExpressionPlus: // '+' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionMinus: // '-' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionCpl: // '~' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionNot: // '!' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionSizeofExpr: // "sizeof" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionSizeofType: // "sizeof" '(' TypeName ')'
panic(todo("", p.pos(n)))
case cc.UnaryExpressionLabelAddr: // "&&" IDENTIFIER
panic(todo("", p.pos(n)))
case cc.UnaryExpressionAlignofExpr: // "_Alignof" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionAlignofType: // "_Alignof" '(' TypeName ')'
panic(todo("", p.pos(n)))
case cc.UnaryExpressionImag: // "__imag__" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionReal: // "__real__" UnaryExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) unaryExpressionFunc(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.UnaryExpressionPostfix: // PostfixExpression
p.postfixExpression(f, n.PostfixExpression, t, mode, flags)
case cc.UnaryExpressionInc: // "++" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionDec: // "--" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionAddrof: // '&' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionDeref: // '*' CastExpression
ot := n.CastExpression.Operand.Type()
switch ot.Kind() {
case cc.Ptr:
switch et := ot.Elem(); et.Kind() {
case cc.Function:
p.castExpression(f, n.CastExpression, ot, mode, flags|fAddrOfFuncPtrOk)
case cc.Ptr:
switch et2 := et.Elem(); et2.Kind() {
case cc.Function:
// C: (**)()
p.fnVal(n, f, func() { p.castExpression(f, n.CastExpression, p.ptrType, exprValue, flags|fAddrOfFuncPtrOk) }, n.CastExpression.Declarator(), n.CastExpression.Operand.Type(), 1, mode, flags)
default:
panic(todo("", p.pos(n), et2, et2.Kind()))
}
default:
panic(todo("", p.pos(n), et, et.Kind()))
}
case cc.Function:
p.castExpression(f, n.CastExpression, ot, mode, flags|fAddrOfFuncPtrOk)
default:
panic(todo("", p.pos(n), ot, ot.Kind(), mode))
}
case cc.UnaryExpressionPlus: // '+' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionMinus: // '-' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionCpl: // '~' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionNot: // '!' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionSizeofExpr: // "sizeof" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionSizeofType: // "sizeof" '(' TypeName ')'
panic(todo("", p.pos(n)))
case cc.UnaryExpressionLabelAddr: // "&&" IDENTIFIER
panic(todo("", p.pos(n)))
case cc.UnaryExpressionAlignofExpr: // "_Alignof" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionAlignofType: // "_Alignof" '(' TypeName ')'
panic(todo("", p.pos(n)))
case cc.UnaryExpressionImag: // "__imag__" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionReal: // "__real__" UnaryExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) unaryExpressionPSelect(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.UnaryExpressionPostfix: // PostfixExpression
p.postfixExpression(f, n.PostfixExpression, t, mode, flags)
case cc.UnaryExpressionInc: // "++" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionDec: // "--" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionAddrof: // '&' CastExpression
panic(todo("", n.Position()))
//TODO- p.w("(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type().Elem()))
//TODO- p.unaryExpression(f, n, t, exprValue, flags)
//TODO- p.w("))")
case cc.UnaryExpressionDeref: // '*' CastExpression
panic(todo("", n.Position()))
//TODO- ot := n.CastExpression.Operand.Type()
//TODO- switch ot.Kind() {
//TODO- case cc.Ptr:
//TODO- switch et := ot.Elem(); {
//TODO- case et.Kind() == cc.Ptr:
//TODO- switch et2 := et.Elem(); et2.Kind() {
//TODO- case cc.Struct:
//TODO- if et2.IsIncomplete() {
//TODO- p.w("(*(**uintptr)(unsafe.Pointer(")
//TODO- p.castExpression(f, n.CastExpression, t, exprValue, flags)
//TODO- p.w(")))")
//TODO- break
//TODO- }
//TODO- p.w("(*(**%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type().Elem()))
//TODO- p.castExpression(f, n.CastExpression, t, exprValue, flags)
//TODO- p.w(")))")
//TODO- default:
//TODO- panic(todo("", p.pos(n), et2, et2.Kind()))
//TODO- }
//TODO- default:
//TODO- panic(todo("", p.pos(n), et, et.Kind()))
//TODO- }
//TODO- default:
//TODO- panic(todo("", p.pos(n), ot, ot.Kind()))
//TODO- }
case cc.UnaryExpressionPlus: // '+' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionMinus: // '-' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionCpl: // '~' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionNot: // '!' CastExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionSizeofExpr: // "sizeof" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionSizeofType: // "sizeof" '(' TypeName ')'
panic(todo("", p.pos(n)))
case cc.UnaryExpressionLabelAddr: // "&&" IDENTIFIER
panic(todo("", p.pos(n)))
case cc.UnaryExpressionAlignofExpr: // "_Alignof" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionAlignofType: // "_Alignof" '(' TypeName ')'
panic(todo("", p.pos(n)))
case cc.UnaryExpressionImag: // "__imag__" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionReal: // "__real__" UnaryExpression
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) unaryExpressionBool(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.UnaryExpressionPostfix: // PostfixExpression
p.postfixExpression(f, n.PostfixExpression, t, mode, flags)
case cc.UnaryExpressionNot: // '!' CastExpression
p.w("!(")
p.castExpression(f, n.CastExpression, t, mode, flags)
p.w(")")
default:
p.w("(")
defer p.w(")")
defer p.w(" != 0 ")
p.unaryExpression(f, n, t, exprValue, flags)
}
}
func (p *project) unaryExpressionAddrOf(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.UnaryExpressionPostfix: // PostfixExpression
p.postfixExpression(f, n.PostfixExpression, t, mode, flags)
case cc.UnaryExpressionInc: // "++" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionDec: // "--" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionAddrof: // '&' CastExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionDeref: // '*' CastExpression
ot := n.CastExpression.Operand.Type()
switch ot.Kind() {
case cc.Ptr:
switch et := ot.Elem(); {
case
et.IsScalarType(),
et.Kind() == cc.Struct,
et.Kind() == cc.Union,
et.Kind() == cc.Array:
p.unaryExpressionDeref(f, n, t, mode, flags)
default:
panic(todo("", p.pos(n), et, et.Kind()))
}
default:
panic(todo("", p.pos(n), ot, ot.Kind()))
}
case cc.UnaryExpressionPlus: // '+' CastExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionMinus: // '-' CastExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionCpl: // '~' CastExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionNot: // '!' CastExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionSizeofExpr: // "sizeof" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionSizeofType: // "sizeof" '(' TypeName ')'
panic(todo("", n.Position()))
case cc.UnaryExpressionLabelAddr: // "&&" IDENTIFIER
panic(todo("", n.Position()))
case cc.UnaryExpressionAlignofExpr: // "_Alignof" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionAlignofType: // "_Alignof" '(' TypeName ')'
panic(todo("", n.Position()))
case cc.UnaryExpressionImag: // "__imag__" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionReal: // "__real__" UnaryExpression
panic(todo("", n.Position()))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) unaryExpressionVoid(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.UnaryExpressionPostfix: // PostfixExpression
p.postfixExpression(f, n.PostfixExpression, t, mode, flags)
case cc.UnaryExpressionInc: // "++" UnaryExpression
p.unaryExpressionPreIncDec(f, n, "++", "+=", t, mode, flags)
case cc.UnaryExpressionDec: // "--" UnaryExpression
p.unaryExpressionPreIncDec(f, n, "--", "-=", t, mode, flags)
case cc.UnaryExpressionAddrof: // '&' CastExpression
p.w("_ = ")
switch {
case n.CastExpression.Operand.Type().Kind() == cc.Array:
panic(todo("", p.pos(n)))
default:
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprAddrOf, flags)
}
case cc.UnaryExpressionDeref: // '*' CastExpression
p.w("_ = *(*byte)(unsafe.Pointer(")
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprValue, flags)
p.w("))")
case
cc.UnaryExpressionPlus, // '+' CastExpression
cc.UnaryExpressionMinus, // '-' CastExpression
cc.UnaryExpressionNot, // '!' CastExpression
cc.UnaryExpressionCpl: // '~' CastExpression
p.w("_ = ")
defer p.w("%s", p.convert(n, n.CastExpression.Operand, p.intType, flags))
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprValue, flags)
case cc.UnaryExpressionSizeofExpr: // "sizeof" UnaryExpression
// nop
case cc.UnaryExpressionSizeofType: // "sizeof" '(' TypeName ')'
// nop
case cc.UnaryExpressionLabelAddr: // "&&" IDENTIFIER
panic(todo("", n.Position()))
case cc.UnaryExpressionAlignofExpr: // "_Alignof" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionAlignofType: // "_Alignof" '(' TypeName ')'
panic(todo("", n.Position()))
case cc.UnaryExpressionImag: // "__imag__" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionReal: // "__real__" UnaryExpression
panic(todo("", n.Position()))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) unaryExpressionValue(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.UnaryExpressionPostfix: // PostfixExpression
p.postfixExpression(f, n.PostfixExpression, t, mode, flags)
case cc.UnaryExpressionInc: // "++" UnaryExpression
p.unaryExpressionPreIncDec(f, n, "++", "+=", t, mode, flags)
case cc.UnaryExpressionDec: // "--" UnaryExpression
p.unaryExpressionPreIncDec(f, n, "--", "-=", t, mode, flags)
case cc.UnaryExpressionAddrof: // '&' CastExpression
if t.Kind() != cc.Ptr {
defer p.w("%s", p.convert(n, n.Operand, t, flags))
}
switch {
case n.CastExpression.Operand.Type().Kind() == cc.Array:
panic(todo("", p.pos(n)))
default:
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprAddrOf, flags)
}
case cc.UnaryExpressionDeref: // '*' CastExpression
ot := n.CastExpression.Operand.Type()
switch ot.Kind() {
case cc.Ptr, cc.Array:
switch et := ot.Elem(); {
case
et.IsScalarType(),
et.Kind() == cc.Array,
et.Kind() == cc.Struct,
et.Kind() == cc.Union:
p.unaryExpressionDeref(f, n, t, mode, flags)
case et.Kind() == cc.Function:
p.castExpression(f, n.CastExpression, t, mode, flags)
default:
panic(todo("", p.pos(n), et, et.Kind()))
}
default:
panic(todo("", p.pos(n), ot, ot.Kind()))
}
case cc.UnaryExpressionPlus: // '+' CastExpression
p.w(" +")
p.castExpression(f, n.CastExpression, t, mode, flags)
case cc.UnaryExpressionMinus: // '-' CastExpression
switch {
case isNonNegativeInt(n.CastExpression.Operand) && t.Kind() == cc.Ptr:
p.w(" -%sUintptr(", p.task.crt)
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprValue, flags)
p.w(")")
case isZeroReal(n.CastExpression.Operand):
p.w(" -")
defer p.w("%s", p.convert(n, n.CastExpression.Operand, t, flags))
p.w("%s%sFrom%[2]s(", p.task.crt, p.helperType(n, n.CastExpression.Operand.Type()))
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprValue, flags)
p.w(")")
case isNonNegativeInt(n.CastExpression.Operand) && isUnsigned(n.Operand.Type()):
defer p.w("%s", p.convert(n, n.CastExpression.Operand, t, flags))
p.w("%sNeg%s(", p.task.crt, p.helperType(n, n.CastExpression.Operand.Type()))
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprValue, flags)
p.w(")")
default:
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w(" -")
p.castExpression(f, n.CastExpression, n.Operand.Type(), exprValue, flags)
}
case cc.UnaryExpressionCpl: // '~' CastExpression
defer p.w("%s", p.convert(n, n.Operand, t, flags))
switch {
case n.CastExpression.Operand.Value() != nil:
switch {
case !t.IsIntegerType():
p.w(" ^")
p.castExpression(f, n.CastExpression, n.Operand.Type(), exprValue, flags|fForceRuntimeConv)
default:
p.w("%sCpl%s(", p.task.crt, p.helperType(n, n.Operand.Type()))
p.castExpression(f, n.CastExpression, n.Operand.Type(), exprValue, flags)
p.w(")")
}
default:
p.w(" ^")
p.castExpression(f, n.CastExpression, n.Operand.Type(), exprValue, flags)
}
case cc.UnaryExpressionNot: // '!' CastExpression
p.w("%sBool%s(!(", p.task.crt, p.helperType(n, t))
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprBool, flags)
p.w("))")
case cc.UnaryExpressionSizeofExpr: // "sizeof" UnaryExpression
p.checkSizeof(n.UnaryExpression, n.UnaryExpression.Operand.Type())
defer p.w("%s", p.convertNil(n, t, flags))
if d := n.UnaryExpression.Declarator(); d != nil {
var isLocal bool
if f != nil {
if local := f.locals[d]; local != nil {
isLocal = true
if !local.isPinned {
p.w("unsafe.Sizeof(%s)", local.name)
return
}
}
}
if !isLocal {
if tld := p.tlds[d]; tld != nil {
p.w("unsafe.Sizeof(%s)", tld.name)
break
}
nm := d.Name().String()
if imp := p.imports[nm]; imp != nil {
imp.used = true
p.w("unsafe.Sizeof(%sX%s)", imp.qualifier, nm)
break
}
}
}
t := n.UnaryExpression.Operand.Type()
if p.isArray(f, n.UnaryExpression, t) {
p.w("%d", t.Len()*t.Elem().Size())
break
}
s := "(0)"
if !t.IsArithmeticType() {
switch t.Kind() {
case cc.Ptr:
// ok
case cc.Struct, cc.Union, cc.Array:
s = "{}"
default:
panic(todo("", t.Kind()))
}
}
switch t.Kind() {
case cc.Int128, cc.UInt128:
s = "{}"
}
p.w("unsafe.Sizeof(%s%s)", p.typ(n, t), s)
case cc.UnaryExpressionSizeofType: // "sizeof" '(' TypeName ')'
defer p.w("%s", p.convertNil(n, t, flags))
t := n.TypeName.Type()
p.checkSizeof(n.TypeName, t)
if t.Kind() == cc.Array {
p.w("%d", t.Len()*t.Elem().Size())
break
}
s := "(0)"
if !t.IsArithmeticType() {
switch t.Kind() {
case cc.Ptr:
// ok
case cc.Struct, cc.Union:
s = "{}"
default:
panic(todo("", t.Kind()))
}
}
switch t.Kind() {
case cc.Int128, cc.UInt128:
s = "{}"
}
p.w("unsafe.Sizeof(%s%s)", p.typ(n, t), s)
case cc.UnaryExpressionLabelAddr: // "&&" IDENTIFIER
panic(todo("", n.Position()))
case cc.UnaryExpressionAlignofExpr: // "_Alignof" UnaryExpression
if n.TypeName.Type().Kind() == cc.Void {
p.intConst(n, "", n.Operand, t, flags)
break
}
defer p.w("%s", p.convertNil(n, t, flags))
t := n.UnaryExpression.Operand.Type()
if p.isArray(f, n.UnaryExpression, t) {
p.w("%d", t.Len()*t.Elem().Size())
break
}
s := "(0)"
if !t.IsArithmeticType() {
switch t.Kind() {
case cc.Ptr:
// ok
case cc.Struct, cc.Union:
s = "{}"
default:
panic(todo("", t.Kind()))
}
}
p.w("unsafe.Alignof(%s%s)", p.typ(n, t), s)
case cc.UnaryExpressionAlignofType: // "_Alignof" '(' TypeName ')'
if n.TypeName.Type().Kind() == cc.Void {
p.intConst(n, "", n.Operand, t, flags)
break
}
defer p.w("%s", p.convertNil(n, t, flags))
t := n.TypeName.Type()
if t.Kind() == cc.Array {
p.w("%d", t.Len()*t.Elem().Size())
break
}
s := "(0)"
if !t.IsArithmeticType() {
switch t.Kind() {
case cc.Ptr:
// ok
case cc.Struct, cc.Union:
s = "{}"
default:
panic(todo("", t.Kind()))
}
}
p.w("unsafe.Alignof(%s%s)", p.typ(n, t), s)
case cc.UnaryExpressionImag: // "__imag__" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionReal: // "__real__" UnaryExpression
panic(todo("", n.Position()))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) checkSizeof(n cc.Node, t cc.Type) {
if !p.checkSizeof0(n, t) {
p.err(n, "sizeof type %s: not supported", t.Alias())
}
}
func (p *project) checkSizeof0(n cc.Node, t cc.Type) (ok bool) {
switch t.Kind() {
case cc.Array:
return !t.IsVLA()
case cc.Struct, cc.Union:
nf := t.NumField()
for i := []int{0}; i[0] < nf; i[0]++ {
if !p.checkSizeof0(n, t.FieldByIndex(i).Type()) {
return false
}
}
}
return true
}
func (p *project) unaryExpressionLValue(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.UnaryExpressionPostfix: // PostfixExpression
p.postfixExpression(f, n.PostfixExpression, t, mode, flags)
case cc.UnaryExpressionInc: // "++" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionDec: // "--" UnaryExpression
panic(todo("", p.pos(n)))
case cc.UnaryExpressionAddrof: // '&' CastExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionDeref: // '*' CastExpression
ot := n.CastExpression.Operand.Type()
switch ot.Kind() {
case cc.Ptr, cc.Array:
switch et := ot.Elem(); {
case
et.IsScalarType(),
et.Kind() == cc.Struct,
et.Kind() == cc.Union:
p.unaryExpressionDeref(f, n, t, mode, flags)
default:
panic(todo("", p.pos(n), et, et.Kind()))
}
default:
panic(todo("", p.pos(n), ot, ot.Kind()))
}
case cc.UnaryExpressionPlus: // '+' CastExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionMinus: // '-' CastExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionCpl: // '~' CastExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionNot: // '!' CastExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionSizeofExpr: // "sizeof" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionSizeofType: // "sizeof" '(' TypeName ')'
panic(todo("", n.Position()))
case cc.UnaryExpressionLabelAddr: // "&&" IDENTIFIER
panic(todo("", n.Position()))
case cc.UnaryExpressionAlignofExpr: // "_Alignof" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionAlignofType: // "_Alignof" '(' TypeName ')'
panic(todo("", n.Position()))
case cc.UnaryExpressionImag: // "__imag__" UnaryExpression
panic(todo("", n.Position()))
case cc.UnaryExpressionReal: // "__real__" UnaryExpression
panic(todo("", n.Position()))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func isSigned(t cc.Type) bool { return t.IsIntegerType() && t.IsSignedType() }
func isUnsigned(t cc.Type) bool { return t.IsIntegerType() && !t.IsSignedType() }
func isConstInteger(op cc.Operand) bool {
switch op.Value().(type) {
case cc.Int64Value, cc.Uint64Value:
return true
default:
return false
}
}
func isNegativeInt(op cc.Operand) bool {
switch x := op.Value().(type) {
case cc.Int64Value:
return x < 0
default:
return false
}
}
func isNonNegativeInt(op cc.Operand) bool {
switch x := op.Value().(type) {
case cc.Int64Value:
return x >= 0
case cc.Uint64Value:
return true
default:
return false
}
}
func (p *project) unaryExpressionPreIncDec(f *function, n *cc.UnaryExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
// "++" UnaryExpression etc.
switch mode {
case exprValue:
p.unaryExpressionPreIncDecValue(f, n, oper, oper2, t, mode, flags)
case exprVoid:
p.unaryExpressionPreIncDecVoid(f, n, oper, oper2, t, mode, flags)
default:
panic(todo("", p.pos(n), mode))
}
}
func (p *project) unaryExpressionPreIncDecVoid(f *function, n *cc.UnaryExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
// "++" UnaryExpression etc.
switch n.UnaryExpression.Operand.Type().Kind() {
case cc.Int128, cc.UInt128:
p.unaryExpressionLValue(f, n.UnaryExpression, n.UnaryExpression.Operand.Type(), exprLValue, 0)
switch oper {
case "++":
p.w(".LValueInc()")
case "--":
p.w(".LValueDec()")
default:
panic(todo("internal error: %q", oper))
}
return
}
// "++" UnaryExpression etc.
switch k := p.opKind(f, n.UnaryExpression, n.UnaryExpression.Operand.Type()); k {
case opNormal:
p.unaryExpressionPreIncDecVoidNormal(f, n, oper, oper2, t, mode, flags)
case opArrayParameter:
p.unaryExpressionPreIncDecVoidArrayParameter(f, n, oper, oper2, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) unaryExpressionPreIncDecVoidArrayParameter(f *function, n *cc.UnaryExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
// "++" UnaryExpression etc.
ut := n.UnaryExpression.Operand.Type()
p.unaryExpression(f, n.UnaryExpression, n.UnaryExpression.Operand.Type(), exprLValue, flags)
switch d := p.incDelta(n, ut); d {
case 1:
p.w("%s", oper)
default:
p.w("%s %d", oper2, d)
}
}
func (p *project) unaryExpressionPreIncDecVoidNormal(f *function, n *cc.UnaryExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
// "++" UnaryExpression etc.
ut := n.UnaryExpression.Operand.Type()
if d := n.UnaryExpression.Declarator(); d != nil && p.isVolatileOrAtomic(d) {
x := "Dec"
if oper == "++" {
x = "Inc"
}
p.w("%sPre%sAtomic%s(&", p.task.crt, x, p.helperType(n, d.Type()))
switch local, tld := f.locals[d], p.tlds[d]; {
case local != nil:
p.w("%s", local.name)
case tld != nil:
p.w("%s", tld.name)
default:
panic(todo(""))
}
p.w(", %d)", p.incDelta(n.PostfixExpression, ut))
return
}
p.unaryExpression(f, n.UnaryExpression, n.UnaryExpression.Operand.Type(), exprLValue, flags)
if ut.IsIntegerType() || ut.Kind() == cc.Ptr && p.incDelta(n, ut) == 1 {
p.w("%s", oper)
return
}
switch ut.Kind() {
case cc.Ptr, cc.Double, cc.Float:
p.w("%s %d", oper2, p.incDelta(n, ut))
return
}
panic(todo("", p.pos(n)))
}
func (p *project) unaryExpressionPreIncDecValue(f *function, n *cc.UnaryExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
// "++" UnaryExpression etc.
switch k := p.opKind(f, n.UnaryExpression, n.UnaryExpression.Operand.Type()); k {
case opNormal:
p.unaryExpressionPreIncDecValueNormal(f, n, oper, oper2, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) unaryExpressionPreIncDecValueNormal(f *function, n *cc.UnaryExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
// "++" UnaryExpression etc.
defer p.w("%s", p.convert(n, n.UnaryExpression.Operand, t, flags))
x := "Dec"
if oper == "++" {
x = "Inc"
}
ut := n.UnaryExpression.Operand.Type()
if d := n.UnaryExpression.Declarator(); d != nil && p.isVolatileOrAtomic(d) {
if !ut.IsIntegerType() {
panic(todo("", n.Position(), d.Position(), ut))
}
flags |= fVolatileOk
switch ut.Size() {
case 4:
switch {
case ut.IsSignedType():
p.w("%sPre%sInt32(&", p.task.crt, x)
p.unaryExpression(f, n.UnaryExpression, ut, exprLValue, flags)
p.w(", 1)")
default:
p.w("%sPre%sInt32((*int32)(unsafe.Pointer(&", p.task.crt, x)
p.unaryExpression(f, n.UnaryExpression, ut, exprLValue, flags)
p.w(")), 1)")
}
case 8:
switch {
case ut.IsSignedType():
p.w("%sPre%sInt64(&", p.task.crt, x)
p.unaryExpression(f, n.UnaryExpression, ut, exprLValue, flags)
p.w(", 1)")
default:
p.w("%sPre%sInt64((*int64)(unsafe.Pointer(&", p.task.crt, x)
p.unaryExpression(f, n.UnaryExpression, ut, exprLValue, flags)
p.w(")), 1)")
}
default:
panic(todo("", n.Position(), d.Position(), ut))
}
return
}
p.w("%sPre%s%s(&", p.task.crt, x, p.helperType(n, ut))
p.unaryExpression(f, n.UnaryExpression, ut, exprLValue, flags)
p.w(", %d)", p.incDelta(n.PostfixExpression, ut))
}
func (p *project) unaryExpressionDeref(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
// '*' CastExpression
switch mode {
case exprValue:
p.unaryExpressionDerefValue(f, n, t, mode, flags)
case exprLValue:
p.unaryExpressionDerefLValue(f, n, t, mode, flags)
case exprAddrOf:
p.unaryExpressionDerefAddrOf(f, n, t, mode, flags)
case exprBool:
p.unaryExpressionDerefBool(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) unaryExpressionDerefBool(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
// '*' CastExpression
p.w("(")
defer p.w(")")
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprValue, flags)
p.w(")) != 0")
}
func (p *project) unaryExpressionDerefAddrOf(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
// '*' CastExpression
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprValue, flags)
}
func (p *project) unaryExpressionDerefLValue(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
// '*' CastExpression
switch k := p.opKind(f, n.CastExpression, n.CastExpression.Operand.Type()); k {
case opNormal:
p.unaryExpressionDerefLValueNormal(f, n, t, mode, flags)
case opArray:
panic(todo("", p.pos(n)))
p.unaryExpressionDerefLValueArray(f, n, t, mode, flags)
case opArrayParameter:
p.unaryExpressionDerefLValueNormal(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) unaryExpressionDerefLValueArray(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
defer p.w("))%s", p.convertType(n, n.CastExpression.Operand.Type().Elem(), t, flags))
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprValue, flags)
}
func (p *project) unaryExpressionDerefLValueNormal(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
defer p.w("))%s", p.convertType(n, n.CastExpression.Operand.Type().Elem(), t, flags))
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprValue, flags)
}
func (p *project) unaryExpressionDerefValue(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
// '*' CastExpression
switch k := p.opKind(f, n.CastExpression, n.CastExpression.Operand.Type()); k {
case opNormal, opArrayParameter:
p.unaryExpressionDerefValueNormal(f, n, t, mode, flags)
case opArray:
p.unaryExpressionDerefValueArray(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) unaryExpressionDerefValueArray(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
defer p.w("%s", p.convertType(n, n.CastExpression.Operand.Type().Elem(), t, flags))
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), exprValue, flags)
p.w("[0]")
}
func (p *project) unaryExpressionDerefValueNormal(f *function, n *cc.UnaryExpression, t cc.Type, mode exprMode, flags flags) {
// '*' CastExpression
switch op := n.Operand.Type(); {
case op.Kind() == cc.Array:
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), mode, flags)
default:
defer p.w("))%s", p.convertType(n, n.CastExpression.Operand.Type().Elem(), t, flags))
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.castExpression(f, n.CastExpression, n.CastExpression.Operand.Type(), mode, flags)
}
}
func (p *project) postfixExpression(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprLValue:
p.postfixExpressionLValue(f, n, t, mode, flags)
case exprValue:
p.postfixExpressionValue(f, n, t, mode, flags)
case exprVoid:
p.postfixExpressionVoid(f, n, t, mode, flags)
case exprFunc:
p.postfixExpressionFunc(f, n, t, mode, flags)
case exprAddrOf:
p.postfixExpressionAddrOf(f, n, t, mode, flags)
case exprSelect:
p.postfixExpressionSelect(f, n, t, mode, flags)
case exprPSelect:
p.postfixExpressionPSelect(f, n, t, mode, flags)
case exprBool:
p.postfixExpressionBool(f, n, t, mode, flags)
case exprDecay:
p.postfixExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) postfixExpressionDecay(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PostfixExpressionPrimary: // PrimaryExpression
p.primaryExpression(f, n.PrimaryExpression, t, mode, flags)
case cc.PostfixExpressionIndex: // PostfixExpression '[' Expression ']'
defer p.w("%s", p.convert(n, n.Operand, t, flags))
pe := n.PostfixExpression.Operand.Type()
p.w("(")
switch {
case pe.Kind() == cc.Array:
p.postfixExpression(f, n.PostfixExpression, pe, exprDecay, flags)
case pe.Kind() == cc.Ptr:
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
default:
panic(todo("", p.pos(n)))
}
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
p.w(")")
case cc.PostfixExpressionCall: // PostfixExpression '(' ArgumentExpressionList ')'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER
p.postfixExpression(f, n, t, exprAddrOf, flags)
case cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
p.postfixExpression(f, n, t, exprAddrOf, flags)
case cc.PostfixExpressionInc: // PostfixExpression "++"
panic(todo("", p.pos(n)))
case cc.PostfixExpressionDec: // PostfixExpression "--"
panic(todo("", p.pos(n)))
case cc.PostfixExpressionComplit: // '(' TypeName ')' '{' InitializerList ',' '}'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionTypeCmp: // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionChooseExpr:
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) postfixExpressionBool(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PostfixExpressionPrimary: // PrimaryExpression
p.primaryExpression(f, n.PrimaryExpression, t, mode, flags)
case cc.PostfixExpressionIndex: // PostfixExpression '[' Expression ']'
p.w("(")
defer p.w(")")
defer p.w(" != 0")
p.postfixExpression(f, n, t, exprValue, flags)
case cc.PostfixExpressionCall: // PostfixExpression '(' ArgumentExpressionList ')'
p.postfixExpressionCall(f, n, t, mode, flags)
case cc.PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER
p.w("(")
defer p.w(")")
defer p.w(" != 0")
p.postfixExpression(f, n, t, exprValue, flags)
case cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
p.w("(")
defer p.w(")")
defer p.w(" != 0")
p.postfixExpression(f, n, t, exprValue, flags)
case cc.PostfixExpressionInc: // PostfixExpression "++"
p.w("(")
defer p.w(")")
defer p.w(" != 0")
p.postfixExpression(f, n, t, exprValue, flags)
case cc.PostfixExpressionDec: // PostfixExpression "--"
p.w("(")
defer p.w(")")
defer p.w(" != 0")
p.postfixExpression(f, n, t, exprValue, flags)
case cc.PostfixExpressionComplit: // '(' TypeName ')' '{' InitializerList ',' '}'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionTypeCmp: // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionChooseExpr:
p.w("(")
defer p.w(")")
defer p.w(" != 0")
p.postfixExpression(f, n, t, exprValue, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) postfixExpressionPSelect(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
switch n.Case {
case cc.PostfixExpressionPrimary: // PrimaryExpression
p.primaryExpression(f, n.PrimaryExpression, t, mode, flags)
case cc.PostfixExpressionIndex: // PostfixExpression '[' Expression ']'
p.postfixExpressionPSelectIndex(f, n, t, mode, flags)
case cc.PostfixExpressionCall: // PostfixExpression '(' ArgumentExpressionList ')'
p.postfixExpressionPSelectCall(f, n, t, mode, flags)
case cc.PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER
p.postfixExpressionPSelectSelect(f, n, t, mode, flags)
case cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
p.postfixExpressionPSelectPSelect(f, n, t, mode, flags)
case cc.PostfixExpressionInc: // PostfixExpression "++"
panic(todo("", p.pos(n)))
case cc.PostfixExpressionDec: // PostfixExpression "--"
panic(todo("", p.pos(n)))
case cc.PostfixExpressionComplit: // '(' TypeName ')' '{' InitializerList ',' '}'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionTypeCmp: // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionChooseExpr:
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) postfixExpressionPSelectSelect(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
switch k := p.opKind(f, n.PostfixExpression, n.PostfixExpression.Operand.Type()); k {
case opStruct:
p.postfixExpressionPSelectSelectStruct(f, n, t, mode, flags)
case opUnion:
p.postfixExpressionPSelectSelectUnion(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) postfixExpressionPSelectSelectUnion(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
fld := n.Field
if fld.Offset() != 0 {
p.err(&n.Token2, "internal error, union field with non-zero offset: %s %v", n.Token2.Value, fld.Offset())
}
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
pe := n.PostfixExpression.Operand.Type()
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("(*(**%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type().Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprAddrOf, flags)
p.w("/* .%s */", p.fieldName(n, n.Token2.Value))
p.w(")))")
}
}
func (p *project) postfixExpressionPSelectSelectStruct(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
fld := n.Field
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
pe := n.PostfixExpression.Operand.Type()
p.w("(*%s)(unsafe.Pointer(", p.typ(n, t.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprSelect, flags)
p.w(".%s", p.fieldName(n, n.Token2.Value))
p.w("))")
}
}
func (p *project) postfixExpressionPSelectCall(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
p.w("(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type().Elem()))
p.postfixExpressionCall(f, n, t, exprValue, flags)
p.w("))")
}
func (p *project) postfixExpressionPSelectIndex(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '[' Expression ']'
switch k := p.opKind(f, n.PostfixExpression, n.PostfixExpression.Operand.Type()); k {
// case opArray:
// p.postfixExpressionSelectIndexArray(f, n, t, mode, flags)
case opNormal:
p.postfixExpressionPSelectIndexNormal(f, n, t, mode, flags)
case opArrayParameter:
p.postfixExpressionSelectIndexArrayParamater(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) postfixExpressionPSelectIndexNormal(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
pe := n.PostfixExpression.Operand.Type()
// PostfixExpression '[' Expression ']'
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
case n.Operand.Type().Kind() == cc.Array:
panic(todo("", p.pos(n)))
case pe.Kind() == cc.Array:
p.w("(")
defer p.w(")")
p.w("(*(**%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type().Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprAddrOf, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Decay().Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
p.w(")))")
default:
p.w("(")
defer p.w(")")
p.w("(*(**%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type().Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Decay().Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
p.w(")))")
}
}
func (p *project) postfixExpressionSelect(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
switch n.Case {
case cc.PostfixExpressionPrimary: // PrimaryExpression
p.primaryExpression(f, n.PrimaryExpression, t, mode, flags)
case cc.PostfixExpressionIndex: // PostfixExpression '[' Expression ']'
p.postfixExpressionSelectIndex(f, n, t, mode, flags)
case cc.PostfixExpressionCall: // PostfixExpression '(' ArgumentExpressionList ')'
p.postfixExpression(f, n, t, exprValue, flags)
case cc.PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER
p.postfixExpressionSelectSelect(f, n, t, mode, flags)
case cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
p.postfixExpressionSelectPSelect(f, n, t, mode, flags)
case cc.PostfixExpressionInc: // PostfixExpression "++"
panic(todo("", p.pos(n)))
case cc.PostfixExpressionDec: // PostfixExpression "--"
panic(todo("", p.pos(n)))
case cc.PostfixExpressionComplit: // '(' TypeName ')' '{' InitializerList ',' '}'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionTypeCmp: // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionChooseExpr:
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) postfixExpressionPSelectPSelect(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
switch k := p.opKind(f, n.PostfixExpression, n.PostfixExpression.Operand.Type().Elem()); k {
case opStruct:
p.postfixExpressionPSelectPSelectStruct(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) postfixExpressionPSelectPSelectStruct(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
fld := n.Field
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
pe := n.PostfixExpression.Operand.Type()
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("(*%s)(unsafe.Pointer(", p.typ(n, t.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprPSelect, flags)
p.w(".%s", p.fieldName(n, n.Token2.Value))
p.w("))")
}
}
func (p *project) postfixExpressionSelectPSelect(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
switch k := p.opKind(f, n.PostfixExpression, n.PostfixExpression.Operand.Type().Elem()); k {
case opStruct:
p.postfixExpressionSelectPSelectStruct(f, n, t, mode, flags)
case opUnion:
p.postfixExpressionSelectPSelectUnion(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) postfixExpressionSelectPSelectUnion(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
fld := n.Field
if fld.Offset() != 0 {
p.err(&n.Token2, "internal error, union field with non-zero offset: %s %v", n.Token2.Value, fld.Offset())
}
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
case n.Operand.Type().Kind() == cc.Array:
panic(todo("", p.pos(n)))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
pe := n.PostfixExpression.Operand.Type()
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.w("))")
}
}
func (p *project) postfixExpressionSelectPSelectStruct(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
fld := n.Field
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
pe := n.PostfixExpression.Operand.Type()
defer p.w("%s", p.convert(n, n.Operand, t, flags))
et := n.PostfixExpression.Operand.Type().Elem()
fld, path, ok := et.FieldByName2(n.Token2.Value)
switch {
case !ok:
panic(todo("", n.Token.Position()))
case fld.InUnion():
p.w("(*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.w("%s)))", nonZeroUintptr(pathOff(et, path)))
case len(path) != 1:
panic(todo("", n.Token.Position()))
default:
p.w("(*%s)(unsafe.Pointer(", p.typ(n, pe.Elem()))
switch {
case pe.Kind() == cc.Array:
p.postfixExpression(f, n.PostfixExpression, pe, exprAddrOf, flags)
default:
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
}
p.w(")).%s", p.fieldName(n, n.Token2.Value))
}
}
}
func (p *project) postfixExpressionSelectSelect(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
switch k := p.structOrUnion(n); k {
case opUnion:
p.postfixExpressionSelectSelectUnion(f, n, t, mode, flags)
case opStruct:
p.postfixExpressionSelectSelectStruct(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) structOrUnion(n *cc.PostfixExpression) opKind {
t := n.PostfixExpression.Operand.Type()
switch n.Case {
case cc.PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER
// ok
case cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
if t.Kind() == cc.Ptr {
t = t.Elem()
break
}
p.err(n, "expected pointer type: %s", t)
return opStruct
}
f, path, ok := t.FieldByName2(n.Token2.Src)
if !ok {
p.err(&n.Token, "unknown field: %s", n.Token2)
return opStruct
}
for len(path) > 1 {
f = t.FieldByIndex(path[:1])
path = path[1:]
t = f.Type()
}
if t.Kind() == cc.Union {
// trc("%v: %q %v", n.Token2.Position(), n.Token2.Src, opUnion)
return opUnion
}
// trc("%v: %q %v", n.Token2.Position(), n.Token2.Src, opStruct)
return opStruct
}
func (p *project) postfixExpressionSelectSelectStruct(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
fld := n.Field
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
case n.Operand.Type().Kind() == cc.Array:
panic(todo("", p.pos(n)))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
pe := n.PostfixExpression.Operand.Type()
p.postfixExpression(f, n.PostfixExpression, pe, exprSelect, flags)
p.w(".%s", p.fieldName(n, n.Token2.Value))
}
}
func (p *project) postfixExpressionSelectSelectUnion(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
fld := n.Field
if fld.Offset() != 0 {
p.err(&n.Token2, "internal error, union field with non-zero offset: %s %v", n.Token2.Value, fld.Offset())
}
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
case n.Operand.Type().Kind() == cc.Array:
panic(todo("", p.pos(n)))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
pe := n.PostfixExpression.Operand.Type()
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.postfixExpression(f, n.PostfixExpression, pe, exprAddrOf, flags)
p.w("))")
}
}
func (p *project) postfixExpressionSelectIndex(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '[' Expression ']'
switch k := p.opKind(f, n.PostfixExpression, n.PostfixExpression.Operand.Type()); k {
case opArray:
p.postfixExpressionSelectIndexArray(f, n, t, mode, flags)
case opNormal:
p.postfixExpressionSelectIndexNormal(f, n, t, mode, flags)
case opArrayParameter:
p.postfixExpressionSelectIndexArrayParamater(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) postfixExpressionSelectIndexArrayParamater(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
pe := n.PostfixExpression.Operand.Type()
// PostfixExpression '[' Expression ']'
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
case n.Operand.Type().Kind() == cc.Array:
panic(todo("", p.pos(n)))
default:
p.w("(*%s)(unsafe.Pointer(", p.typ(n, pe.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Decay().Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
p.w("))")
}
}
func (p *project) postfixExpressionSelectIndexNormal(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
pe := n.PostfixExpression.Operand.Type()
// PostfixExpression '[' Expression ']'
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
case n.Operand.Type().Kind() == cc.Array:
panic(todo("", p.pos(n)))
case pe.Kind() != cc.Ptr:
p.w("(*%s)(unsafe.Pointer(", p.typ(n, pe.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprAddrOf, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Decay().Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
p.w("))")
default:
p.w("(*%s)(unsafe.Pointer(", p.typ(n, pe.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Decay().Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
p.w("))")
}
}
func (p *project) postfixExpressionSelectIndexArray(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '[' Expression ']'
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
case n.Operand.Type().Kind() == cc.Array:
panic(todo("", p.pos(n)))
default:
pe := n.PostfixExpression.Operand.Type()
p.postfixExpression(f, n.PostfixExpression, pe, mode, flags)
p.w("[")
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags)
p.w("]")
}
}
func (p *project) postfixExpressionAddrOf(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PostfixExpressionPrimary: // PrimaryExpression
p.primaryExpression(f, n.PrimaryExpression, t, mode, flags)
case cc.PostfixExpressionIndex: // PostfixExpression '[' Expression ']'
p.postfixExpressionAddrOfIndex(f, n, t, mode, flags)
case cc.PostfixExpressionCall: // PostfixExpression '(' ArgumentExpressionList ')'
ot := n.Operand.Type()
switch ot.Kind() {
case cc.Struct, cc.Union:
// ok
default:
p.err(n, "cannot take address of value of type %v", n.Operand.Type())
return
}
if p.pass1 {
off := roundup(f.off, uintptr(ot.Align()))
f.complits[n] = off
f.off += ot.Size()
return
}
off := f.complits[n]
p.w("func() uintptr { *(*%s)(unsafe.Pointer(%s%s)) = ", p.typ(n, ot), f.bpName, nonZeroUintptr(off))
p.postfixExpressionValue(f, n, ot, exprValue, flags)
p.w("; return %s%s }()", f.bpName, nonZeroUintptr(off))
case cc.PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER
p.postfixExpressionAddrOfSelect(f, n, t, mode, flags)
case cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
p.postfixExpressionAddrOfPSelect(f, n, t, mode, flags)
case cc.PostfixExpressionInc: // PostfixExpression "++"
p.postfixExpressionIncDec(f, n, "++", "+=", t, exprLValue, flags)
case cc.PostfixExpressionDec: // PostfixExpression "--"
panic(todo("", p.pos(n)))
case cc.PostfixExpressionComplit: // '(' TypeName ')' '{' InitializerList ',' '}'
tn := n.TypeName.Type()
switch tn.Decay().Kind() {
case cc.Ptr:
switch tn.Kind() {
case cc.Array:
switch {
case p.pass1:
off := roundup(f.off, uintptr(tn.Elem().Align()))
f.complits[n] = off
f.off += tn.Size()
default:
off := f.complits[n]
p.w(" func() uintptr { *(*%s)(unsafe.Pointer(%s%s)) = ", p.typ(n, tn), f.bpName, nonZeroUintptr(off))
p.initializer(f, &cc.Initializer{Case: cc.InitializerInitList, InitializerList: n.InitializerList}, tn, cc.Automatic, nil)
p.w("; return %s%s }()", f.bpName, nonZeroUintptr(off))
}
default:
panic(todo("%v: %v", n.Position(), tn))
}
default:
switch {
case p.pass1:
off := roundup(f.off, uintptr(tn.Align()))
f.complits[n] = off
f.off += tn.Size()
default:
off := f.complits[n]
p.w(" func() uintptr { *(*%s)(unsafe.Pointer(%s%s)) = ", p.typ(n, tn), f.bpName, nonZeroUintptr(off))
p.initializer(f, &cc.Initializer{Case: cc.InitializerInitList, InitializerList: n.InitializerList}, tn, cc.Automatic, nil)
p.w("; return %s%s }()", f.bpName, nonZeroUintptr(off))
}
}
case cc.PostfixExpressionTypeCmp: // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionChooseExpr:
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) postfixExpressionAddrOfPSelect(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
p.w("(")
defer p.w(")")
pe := n.PostfixExpression.Operand.Type()
switch {
case n.Operand.Type().IsBitFieldType():
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.bitFldOff(pe.Elem(), n.Token2)
case pe.Kind() == cc.Array:
p.postfixExpression(f, n.PostfixExpression, pe, exprDecay, flags)
p.fldOff(pe.Elem(), n.Token2)
default:
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.fldOff(pe.Elem(), n.Token2)
}
}
func (p *project) postfixExpressionAddrOfIndex(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '[' Expression ']'
p.w("(")
defer p.w(")")
switch {
case n.Operand.Type().Kind() == cc.Array:
fallthrough
default:
pe := n.PostfixExpression.Operand.Type()
d := n.PostfixExpression.Declarator()
switch {
case pe.Kind() == cc.Ptr:
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
case pe.Kind() == cc.Array && d != nil && d.IsParameter:
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
default:
p.postfixExpression(f, n.PostfixExpression, pe, mode, flags)
}
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Decay().Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
}
}
func (p *project) postfixExpressionAddrOfSelect(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
p.w("(")
defer p.w(")")
switch {
case n.Operand.Type().IsBitFieldType():
pe := n.PostfixExpression.Operand.Type()
p.postfixExpression(f, n.PostfixExpression, nil, mode, flags)
p.bitFldOff(pe, n.Token2)
case n.Operand.Type().Kind() == cc.Array:
fallthrough
default:
pe := n.PostfixExpression.Operand.Type()
p.postfixExpression(f, n.PostfixExpression, nil, mode, flags)
p.fldOff(pe, n.Token2)
}
}
func (p *project) postfixExpressionFunc(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PostfixExpressionPrimary: // PrimaryExpression
p.primaryExpression(f, n.PrimaryExpression, t, mode, flags)
case cc.PostfixExpressionIndex: // PostfixExpression '[' Expression ']'
switch n.Operand.Type().Kind() {
case cc.Ptr:
switch et := n.Operand.Type().Elem(); et.Kind() {
case cc.Function:
p.fnVal(n, f, func() {
p.postfixExpression(f, n, n.Operand.Type(), exprValue, flags)
}, nil, n.Operand.Type(), 0, mode, flags)
default:
panic(todo("", p.pos(n), et, et.Kind()))
}
default:
panic(todo("", n.Position(), n.Operand.Type()))
}
case cc.PostfixExpressionCall: // PostfixExpression '(' ArgumentExpressionList ')'
switch n.Operand.Type().Kind() {
case cc.Ptr:
switch et := n.Operand.Type().Elem(); et.Kind() {
case cc.Function:
p.fnVal(n, f, func() {
p.postfixExpressionCall(f, n, t, exprValue, flags)
}, nil, n.Operand.Type(), 0, mode, flags)
default:
panic(todo("", p.pos(n), et, et.Kind()))
}
default:
panic(todo("", n.Position(), n.Operand.Type()))
}
case cc.PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER
switch n.Operand.Type().Kind() {
case cc.Ptr:
switch n.Operand.Type().Kind() {
case cc.Ptr:
switch et := n.Operand.Type().Elem(); et.Kind() {
case cc.Function:
p.fnVal(n, f, func() { p.postfixExpression(f, n, p.ptrType, exprValue, flags) }, nil, n.Operand.Type(), 0, mode, flags)
default:
panic(todo("", p.pos(n), et, et.Kind()))
}
default:
panic(todo("", p.pos(n), n.Operand.Type(), n.Operand.Type().Kind()))
}
default:
panic(todo("", n.Position(), n.Operand.Type()))
}
case cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
p.fnVal(n, f, func() { p.postfixExpression(f, n, p.ptrType, exprValue, flags) }, nil, n.Operand.Type(), 0, mode, flags)
case cc.PostfixExpressionInc: // PostfixExpression "++"
panic(todo("", p.pos(n)))
case cc.PostfixExpressionDec: // PostfixExpression "--"
panic(todo("", p.pos(n)))
case cc.PostfixExpressionComplit: // '(' TypeName ')' '{' InitializerList ',' '}'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionTypeCmp: // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionChooseExpr:
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) postfixExpressionVoid(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PostfixExpressionPrimary: // PrimaryExpression
p.primaryExpression(f, n.PrimaryExpression, t, mode, flags)
case cc.PostfixExpressionIndex: // PostfixExpression '[' Expression ']'
p.w("_ = ")
p.postfixExpression(f, n, n.Operand.Type(), exprValue, flags)
case cc.PostfixExpressionCall: // PostfixExpression '(' ArgumentExpressionList ')'
p.postfixExpressionCall(f, n, n.Operand.Type(), mode, flags)
case cc.PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER
p.w("_ = ")
p.postfixExpression(f, n, n.Operand.Type(), exprValue, flags)
case cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
p.w("_ = ")
p.postfixExpression(f, n, n.Operand.Type(), exprValue, flags)
case cc.PostfixExpressionInc: // PostfixExpression "++"
p.postfixExpressionIncDec(f, n, "++", "+=", t, mode, flags)
case cc.PostfixExpressionDec: // PostfixExpression "--"
p.postfixExpressionIncDec(f, n, "--", "-=", t, mode, flags)
case cc.PostfixExpressionComplit: // '(' TypeName ')' '{' InitializerList ',' '}'
tn := n.TypeName.Type()
switch tn.Decay().Kind() {
case cc.Ptr:
switch tn.Kind() {
case cc.Array:
switch {
case p.pass1:
off := roundup(f.off, uintptr(tn.Elem().Align()))
f.complits[n] = off
f.off += tn.Size()
default:
off := f.complits[n]
p.w("*(*%s)(unsafe.Pointer(%s%s)) = ", p.typ(n, tn), f.bpName, nonZeroUintptr(off))
p.initializer(f, &cc.Initializer{Case: cc.InitializerInitList, InitializerList: n.InitializerList}, tn, cc.Automatic, nil)
}
return
default:
panic(todo("%v: %v", n.Position(), tn))
}
}
defer p.w("%s", p.convertType(n, tn, t, flags))
p.w("_ = ")
p.initializer(f, &cc.Initializer{Case: cc.InitializerInitList, InitializerList: n.InitializerList}, tn, cc.Automatic, nil)
case cc.PostfixExpressionTypeCmp: // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionChooseExpr:
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) postfixExpressionValue(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PostfixExpressionPrimary: // PrimaryExpression
if p.isArray(f, n.PrimaryExpression, n.Operand.Type()) && t.Kind() == cc.Ptr {
mode = exprDecay
}
p.primaryExpression(f, n.PrimaryExpression, t, mode, flags)
case cc.PostfixExpressionIndex: // PostfixExpression '[' Expression ']'
p.postfixExpressionValueIndex(f, n, t, mode, flags)
case cc.PostfixExpressionCall: // PostfixExpression '(' ArgumentExpressionList ')'
p.postfixExpressionCall(f, n, t, mode, flags)
case cc.PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER
p.postfixExpressionValueSelect(f, n, t, mode, flags)
case cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
p.postfixExpressionValuePSelect(f, n, t, mode, flags)
case cc.PostfixExpressionInc: // PostfixExpression "++"
p.postfixExpressionIncDec(f, n, "++", "+=", t, mode, flags)
case cc.PostfixExpressionDec: // PostfixExpression "--"
p.postfixExpressionIncDec(f, n, "--", "-=", t, mode, flags)
case cc.PostfixExpressionComplit: // '(' TypeName ')' '{' InitializerList ',' '}'
tn := n.TypeName.Type()
switch tn.Decay().Kind() {
case cc.Ptr:
switch tn.Kind() {
case cc.Array:
switch {
case p.pass1:
off := roundup(f.off, uintptr(tn.Elem().Align()))
f.complits[n] = off
f.off += tn.Size()
default:
off := f.complits[n]
p.w(" func() uintptr { *(*%s)(unsafe.Pointer(%s%s)) = ", p.typ(n, tn), f.bpName, nonZeroUintptr(off))
p.initializer(f, &cc.Initializer{Case: cc.InitializerInitList, InitializerList: n.InitializerList}, tn, cc.Automatic, nil)
p.w("; return %s%s }()", f.bpName, nonZeroUintptr(off))
}
return
default:
panic(todo("%v: %v", n.Position(), tn))
}
}
defer p.w("%s", p.convertType(n, tn, t, flags))
p.initializer(f, &cc.Initializer{Case: cc.InitializerInitList, InitializerList: n.InitializerList}, tn, cc.Automatic, nil)
case cc.PostfixExpressionTypeCmp: // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')'
// Built-in Function: int __builtin_types_compatible_p (type1, type2) You can
// use the built-in function __builtin_types_compatible_p to determine whether
// two types are the same.
//
// This built-in function returns 1 if the unqualified versions of the types
// type1 and type2 (which are types, not expressions) are compatible, 0
// otherwise. The result of this built-in function can be used in integer
// constant expressions.
//
// This built-in function ignores top level qualifiers (e.g., const, volatile).
// For example, int is equivalent to const int.
//
// The type int[] and int[5] are compatible. On the other hand, int and char *
// are not compatible, even if the size of their types, on the particular
// architecture are the same. Also, the amount of pointer indirection is taken
// into account when determining similarity. Consequently, short * is not
// similar to short **. Furthermore, two types that are typedefed are
// considered compatible if their underlying types are compatible.
//
// An enum type is not considered to be compatible with another enum type even
// if both are compatible with the same integer type; this is what the C
// standard specifies. For example, enum {foo, bar} is not similar to enum
// {hot, dog}.
//
// You typically use this function in code whose execution varies depending on
// the arguments types. For example:
//
// #define foo(x) \
// ({ \
// typeof (x) tmp = (x); \
// if (__builtin_types_compatible_p (typeof (x), long double)) \
// tmp = foo_long_double (tmp); \
// else if (__builtin_types_compatible_p (typeof (x), double)) \
// tmp = foo_double (tmp); \
// else if (__builtin_types_compatible_p (typeof (x), float)) \
// tmp = foo_float (tmp); \
// else \
// abort (); \
// tmp; \
// })
//
// Note: This construct is only available for C.
p.w(" %d ", n.Operand.Value())
case cc.PostfixExpressionChooseExpr: // "__builtin_choose_expr" '(' AssignmentExpression ',' AssignmentExpression ',' AssignmentExpression ')'
// You can use the built-in function __builtin_choose_expr to evaluate code
// depending on the value of a constant expression. This built-in function
// returns exp1 if const_exp, which is an integer constant expression, is
// nonzero. Otherwise it returns exp2.
//
// This built-in function is analogous to the ? : operator in C, except that
// the expression returned has its type unaltered by promotion rules. Also, the
// built-in function does not evaluate the expression that is not chosen. For
// example, if const_exp evaluates to true, exp2 is not evaluated even if it
// has side effects.
//
// This built-in function can return an lvalue if the chosen argument is an
// lvalue.
//
// If exp1 is returned, the return type is the same as exp1s type. Similarly,
// if exp2 is returned, its return type is the same as exp2.
//
// Example:
//
// #define foo(x) \
// __builtin_choose_expr ( \
// __builtin_types_compatible_p (typeof (x), double), \
// foo_double (x), \
// __builtin_choose_expr ( \
// __builtin_types_compatible_p (typeof (x), float), \
// foo_float (x), \
// /* The void expression results in a compile-time error \
// when assigning the result to something. */ \
// (void)0))
//
// Note: This construct is only available for C. Furthermore, the unused
// expression (exp1 or exp2 depending on the value of const_exp) may still
// generate syntax errors. This may change in future revisions.
switch op := n.AssignmentExpression.Operand; {
case op.IsNonZero():
p.assignmentExpression(f, n.AssignmentExpression2, t, mode, flags)
case op.IsZero():
p.assignmentExpression(f, n.AssignmentExpression3, t, mode, flags)
default:
panic(todo(""))
}
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) postfixExpressionValuePSelect(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
switch k := p.opKind(f, n.PostfixExpression, n.PostfixExpression.Operand.Type().Elem()); k {
case opStruct:
p.postfixExpressionValuePSelectStruct(f, n, t, mode, flags)
case opUnion:
p.postfixExpressionValuePSelectUnion(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) postfixExpressionValuePSelectUnion(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
fld := n.Field
if fld.Offset() != 0 {
p.err(&n.Token2, "internal error, union field with non-zero offset: %s %v", n.Token2.Value, fld.Offset())
}
pe := n.PostfixExpression.Operand.Type()
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
case n.Operand.Type().Kind() == cc.Array:
panic(todo("", p.pos(n)))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.w("/* .%s */", p.fieldName(n, n.Token2.Value))
p.w("))")
}
}
func (p *project) postfixExpressionValuePSelectStruct(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
fld := n.Field
pe := n.PostfixExpression.Operand.Type()
k := p.opKind(f, n.PostfixExpression, n.PostfixExpression.Operand.Type())
switch {
case n.Operand.Type().IsBitFieldType():
p.w("(")
defer p.w(")")
fld := n.Field
defer p.w("%s", p.convertType(n, fld.Promote(), t, flags))
switch pe.Kind() {
case cc.Array:
x := p.convertType(n, nil, fld.Promote(), flags)
p.w("*(*uint%d)(unsafe.Pointer(", fld.BitFieldBlockWidth())
p.postfixExpression(f, n.PostfixExpression, pe, exprDecay, flags)
p.bitFldOff(pe.Elem(), n.Token2)
p.w("))")
p.w("&%#x>>%d%s", fld.Mask(), fld.BitFieldOffset(), x)
if fld.Type().IsSignedType() {
panic(todo(""))
p.w("<<%d>>%[1]d", int(fld.Promote().Size()*8)-fld.BitFieldWidth())
}
default:
x := p.convertType(n, nil, fld.Promote(), flags)
p.w("*(*uint%d)(unsafe.Pointer(", fld.BitFieldBlockWidth())
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.bitFldOff(pe.Elem(), n.Token2)
p.w("))&%#x>>%d%s", fld.Mask(), fld.BitFieldOffset(), x)
if fld.Type().IsSignedType() {
p.w("<<%d>>%[1]d", int(fld.Promote().Size()*8)-fld.BitFieldWidth())
}
}
case n.Operand.Type().Kind() == cc.Array:
defer p.w("%s", p.convertType(n, n.Operand.Type().Decay(), t.Decay(), flags))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.fldOff(n.PostfixExpression.Operand.Type().Elem(), n.Token2)
case k == opArray:
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.w("[0].%s", p.fieldName(n, n.Token2.Value))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
defer p.w("%s", p.convert(n, n.Operand, t, flags))
et := pe.Elem()
fld, path, ok := et.FieldByName2(n.Token2.Value)
switch {
case !ok:
panic(todo(""))
case fld.InUnion():
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.w("%s))", nonZeroUintptr(pathOff(et, path)))
case len(path) != 1:
panic(todo(""))
default:
p.w("(*%s)(unsafe.Pointer(", p.typ(n, pe.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.w(")).%s", p.fieldName(n, n.Token2.Value))
}
}
}
func pathOff(t cc.Type, path []int) (r uintptr) {
for len(path) != 0 {
f := t.FieldByIndex(path[:1])
r += f.Offset()
path = path[1:]
t = f.Type()
}
return r
}
func (p *project) postfixExpressionValueIndex(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '[' Expression ']'
switch k := p.opKind(f, n.PostfixExpression, n.PostfixExpression.Operand.Type()); k {
case opArray:
p.postfixExpressionValueIndexArray(f, n, t, mode, flags)
case opNormal:
p.postfixExpressionValueIndexNormal(f, n, t, mode, flags)
case opArrayParameter:
p.postfixExpressionValueIndexArrayParameter(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) postfixExpressionValueIndexArrayParameter(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '[' Expression ']'
pe := n.PostfixExpression.Operand.Type()
switch {
case n.Operand.Type().Kind() == cc.Array:
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("(")
defer p.w(")")
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
default:
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, pe.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
p.w("))")
}
}
func (p *project) postfixExpressionValueIndexNormal(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '[' Expression ']'
switch {
case n.Operand.Type().Kind() == cc.Array:
p.w("(")
defer p.w(")")
pe := n.PostfixExpression.Operand.Type()
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
default:
switch pe := n.PostfixExpression.Operand.Type(); pe.Kind() {
case cc.Ptr:
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, pe.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
p.w("))")
case cc.Array:
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, pe.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprDecay, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
p.w("))")
default:
panic(todo("", p.pos(n), pe, pe.Kind()))
}
}
}
func (p *project) postfixExpressionValueIndexArray(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '[' Expression ']'
pe := n.PostfixExpression.Operand.Type()
switch n.Operand.Type().Kind() {
case cc.Array:
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("(")
defer p.w(")")
p.postfixExpression(f, n.PostfixExpression, pe, exprDecay, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
default:
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.postfixExpression(f, n.PostfixExpression, pe, mode, flags)
p.w("[")
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags)
p.w("]")
}
}
func (p *project) postfixExpressionValueSelect(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
switch k := p.opKind(f, n.PostfixExpression, n.PostfixExpression.Operand.Type()); k {
case opStruct:
p.postfixExpressionValueSelectStruct(f, n, t, mode, flags)
case opUnion:
p.postfixExpressionValueSelectUnion(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) postfixExpressionValueSelectUnion(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
pe := n.PostfixExpression.Operand.Type()
fld := n.Field
switch {
case n.Operand.Type().IsBitFieldType():
p.w("(")
defer p.w("%s)", p.convertType(n, fld.Promote(), t, flags))
x := p.convertType(n, nil, fld.Promote(), flags)
p.w("*(*uint%d)(unsafe.Pointer(", fld.BitFieldBlockWidth())
p.postfixExpression(f, n.PostfixExpression, pe, exprAddrOf, flags)
p.bitFldOff(pe, n.Token2)
p.w("))&%#x>>%d%s", fld.Mask(), fld.BitFieldOffset(), x)
if fld.Type().IsSignedType() {
p.w("<<%d>>%[1]d", int(fld.Promote().Size()*8)-fld.BitFieldWidth())
}
case n.Operand.Type().Kind() == cc.Array:
p.postfixExpression(f, n.PostfixExpression, pe, exprAddrOf, flags)
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.postfixExpression(f, n.PostfixExpression, pe, exprAddrOf, flags)
p.w("))")
}
}
func (p *project) postfixExpressionValueSelectStruct(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
pe := n.PostfixExpression.Operand.Type()
fld := n.Field
switch {
case n.Operand.Type().IsBitFieldType():
p.w("(")
defer p.w("%s)", p.convertType(n, fld.Promote(), t, flags))
x := p.convertType(n, nil, fld.Promote(), flags)
p.w("*(*uint%d)(unsafe.Pointer(", fld.BitFieldBlockWidth())
p.postfixExpression(f, n.PostfixExpression, pe, exprAddrOf, flags)
p.bitFldOff(pe, n.Token2)
p.w("))&%#x>>%d%s", fld.Mask(), fld.BitFieldOffset(), x)
if fld.Type().IsSignedType() {
p.w("<<%d>>%[1]d", int(fld.Promote().Size()*8)-fld.BitFieldWidth())
}
case n.Operand.Type().Kind() == cc.Array:
p.postfixExpression(f, n, t, exprDecay, flags)
case fld.InUnion():
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, fld.Type()))
p.postfixExpression(f, n.PostfixExpression, pe, exprAddrOf, flags)
p.fldOff(pe, n.Token2)
p.w("))")
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.postfixExpression(f, n.PostfixExpression, pe, exprSelect, flags)
p.w(".%s", p.fieldName(n, n.Token2.Value))
}
}
func (p *project) postfixExpressionLValue(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PostfixExpressionPrimary: // PrimaryExpression
p.primaryExpression(f, n.PrimaryExpression, t, mode, flags)
case cc.PostfixExpressionIndex: // PostfixExpression '[' Expression ']'
p.postfixExpressionLValueIndex(f, n, t, mode, flags)
case cc.PostfixExpressionCall: // PostfixExpression '(' ArgumentExpressionList ')'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER
p.postfixExpressionLValueSelect(f, n, t, mode, flags)
case cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
p.postfixExpressionLValuePSelect(f, n, t, mode, flags)
case cc.PostfixExpressionInc: // PostfixExpression "++"
p.postfixExpressionIncDec(f, n, "++", "+=", t, mode, flags)
case cc.PostfixExpressionDec: // PostfixExpression "--"
p.postfixExpressionIncDec(f, n, "--", "-=", t, mode, flags)
case cc.PostfixExpressionComplit: // '(' TypeName ')' '{' InitializerList ',' '}'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionTypeCmp: // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')'
panic(todo("", p.pos(n)))
case cc.PostfixExpressionChooseExpr:
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) postfixExpressionLValuePSelect(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
pe := n.PostfixExpression
switch k := p.opKind(f, n.PostfixExpression, n.PostfixExpression.Operand.Type().Elem()); k {
case opStruct:
if !p.inUnion(n, pe.Operand.Type().Elem(), n.Token2.Value) {
p.postfixExpressionLValuePSelectStruct(f, n, t, mode, flags)
break
}
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.postfixExpression(f, pe, pe.Operand.Type(), exprValue, flags)
p.fldOff(pe.Operand.Type().Elem(), n.Token2)
p.w("))")
case opUnion:
p.postfixExpressionLValuePSelectUnion(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) postfixExpressionLValuePSelectUnion(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
fld := n.Field
if fld.Offset() != 0 {
p.err(&n.Token2, "internal error, union field with non-zero offset: %s %v", n.Token2.Value, fld.Offset())
}
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
pe := n.PostfixExpression.Operand.Type()
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("(*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.w("/* .%s */", p.fieldName(n, n.Token2.Value))
p.w(")))")
}
}
func (p *project) postfixExpressionLValuePSelectStruct(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "->" IDENTIFIER
fld := n.Field
pe := n.PostfixExpression.Operand.Type()
k := p.opKind(f, n.PostfixExpression, n.PostfixExpression.Operand.Type())
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
case k == opArray:
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.w("[0].%s", p.fieldName(n, n.Token2.Value))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("(*%s)(unsafe.Pointer(", p.typ(n, pe.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
p.w(")).%s", p.fieldName(n, n.Token2.Value))
}
}
func (p *project) postfixExpressionLValueIndex(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '[' Expression ']'
switch k := p.opKind(f, n.PostfixExpression, n.PostfixExpression.Operand.Type()); k {
case opArray:
p.postfixExpressionLValueIndexArray(f, n, t, mode, flags)
case opNormal:
p.postfixExpressionLValueIndexNormal(f, n, t, mode, flags)
case opArrayParameter:
p.postfixExpressionLValueIndexArrayParameter(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) postfixExpressionLValueIndexArrayParameter(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '[' Expression ']'
defer p.w("%s", p.convert(n, n.Operand, t, flags))
pe := n.PostfixExpression.Operand.Type()
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, pe.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
p.w("))")
}
func (p *project) postfixExpressionLValueIndexNormal(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '[' Expression ']'
switch {
case n.Operand.Type().Kind() == cc.Array:
panic(todo("", p.pos(n)))
default:
switch pe := n.PostfixExpression.Operand.Type(); pe.Kind() {
case cc.Ptr:
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, pe.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprValue, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
p.w("))")
case cc.Array:
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, pe.Elem()))
p.postfixExpression(f, n.PostfixExpression, pe, exprDecay, flags)
if !n.Expression.Operand.IsZero() {
p.nzUintptr(n, func() { p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags) }, n.Expression.Operand)
if sz := pe.Elem().Size(); sz != 1 {
p.w("*%d", sz)
}
}
p.w("))")
default:
panic(todo("", p.pos(n), pe))
}
}
}
func (p *project) postfixExpressionLValueIndexArray(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '[' Expression ']'
pe := n.PostfixExpression.Operand.Type()
p.postfixExpression(f, n.PostfixExpression, pe, mode, flags)
p.w("[")
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprValue, flags)
p.w("]")
}
func (p *project) postfixExpressionLValueSelect(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
pe := n.PostfixExpression
switch k := p.opKind(f, pe, pe.Operand.Type()); k {
case opStruct:
if !p.inUnion(n, pe.Operand.Type(), n.Token2.Value) {
p.postfixExpressionLValueSelectStruct(f, n, t, mode, flags)
break
}
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.postfixExpression(f, pe, pe.Operand.Type(), exprAddrOf, flags)
p.fldOff(pe.Operand.Type(), n.Token2)
p.w("))")
case opUnion:
p.postfixExpressionLValueSelectUnion(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) inUnion(n cc.Node, t cc.Type, fname cc.StringID) bool {
f, ok := t.FieldByName(fname)
if !ok {
p.err(n, "unknown field: %s", fname)
return false
}
return f.InUnion()
}
func (p *project) postfixExpressionLValueSelectUnion(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
fld := n.Field
pe := n.PostfixExpression.Operand.Type()
switch {
case pe.Kind() == cc.Array:
panic(todo("", p.pos(n)))
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, n.Operand.Type()))
p.postfixExpression(f, n.PostfixExpression, pe, exprAddrOf, flags)
nonZeroUintptr(fld.Offset())
p.w("))")
}
}
func (p *project) postfixExpressionLValueSelectStruct(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '.' IDENTIFIER
fld := n.Field
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
default:
if fld.IsBitField() {
p.err(&n.Token2, "internal error, wrong function for accessing a bit field: %s", n.Token2.Value)
}
pe := n.PostfixExpression.Operand.Type()
p.postfixExpression(f, n.PostfixExpression, pe, exprSelect, flags)
p.w(".%s", p.fieldName(n, n.Token2.Value))
}
}
func (p *project) postfixExpressionIncDec(f *function, n *cc.PostfixExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprVoid:
p.postfixExpressionIncDecVoid(f, n, oper, oper2, t, mode, flags)
case exprLValue:
p.postfixExpressionIncDecLValue(f, n, oper, oper2, t, mode, flags)
case exprValue:
p.postfixExpressionIncDecValue(f, n, oper, oper2, t, mode, flags)
default:
panic(todo("", mode))
}
}
func (p *project) postfixExpressionIncDecValue(f *function, n *cc.PostfixExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "++"
pe := n.PostfixExpression.Operand.Type()
switch k := p.opKind(f, n.PostfixExpression, pe); k {
case opNormal:
p.postfixExpressionIncDecValueNormal(f, n, oper, oper2, t, mode, flags)
case opBitfield:
p.postfixExpressionIncDecValueBitfield(f, n, oper, oper2, t, mode, flags)
case opArrayParameter:
p.postfixExpressionIncDecValueArrayParameter(f, n, oper, oper2, t, mode, flags)
default:
panic(todo("", n.Position(), pe, pe.Kind(), k))
}
}
func (p *project) postfixExpressionIncDecValueArrayParameter(f *function, n *cc.PostfixExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "++"
pe := n.PostfixExpression.Operand.Type()
defer p.w("%s", p.convert(n, n.PostfixExpression.Operand, t, flags))
x := "Dec"
if oper == "++" {
x = "Inc"
}
p.w("%sPost%s%s(&", p.task.crt, x, p.helperType(n, pe.Decay()))
p.postfixExpression(f, n.PostfixExpression, pe, exprLValue, flags)
p.w(", %d)", p.incDelta(n.PostfixExpression, pe))
}
func (p *project) postfixExpressionIncDecValueBitfield(f *function, n *cc.PostfixExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "++"
pe := n.PostfixExpression.Operand.Type()
defer p.w("%s", p.convert(n, n.PostfixExpression.Operand, t, flags))
x := "Dec"
if oper == "++" {
x = "Inc"
}
bf := pe.BitField()
p.w("%sPost%sBitFieldPtr%d%s(", p.task.crt, x, bf.BitFieldBlockWidth(), p.bfHelperType(pe))
p.postfixExpression(f, n.PostfixExpression, pe, exprAddrOf, flags)
p.w(", %d, %d, %d, %#x)", p.incDelta(n.PostfixExpression, pe), bf.BitFieldBlockWidth(), bf.BitFieldOffset(), bf.Mask())
}
func (p *project) postfixExpressionIncDecValueNormal(f *function, n *cc.PostfixExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression "++"
pe := n.PostfixExpression.Operand.Type()
defer p.w("%s", p.convert(n, n.PostfixExpression.Operand, t, flags))
x := "Dec"
if oper == "++" {
x = "Inc"
}
if d := n.PostfixExpression.Declarator(); d != nil && p.isVolatileOrAtomic(d) {
p.w("%sPost%sAtomic%s(&", p.task.crt, x, p.helperType(n, pe))
var local *local
var tld *tld
if f != nil {
local = f.locals[d]
}
if local == nil {
tld = p.tlds[d]
}
switch {
case local != nil:
p.w("%s", local.name)
case tld != nil:
p.w("%s", tld.name)
default:
panic(todo(""))
}
p.w(", %d)", p.incDelta(n.PostfixExpression, pe))
return
}
p.w("%sPost%s%s(&", p.task.crt, x, p.helperType(n, pe))
p.postfixExpression(f, n.PostfixExpression, pe, exprLValue, flags)
p.w(", %d)", p.incDelta(n.PostfixExpression, pe))
}
func (p *project) postfixExpressionIncDecLValue(f *function, n *cc.PostfixExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
switch k := p.opKind(f, n, n.Operand.Type()); k {
case opNormal:
p.postfixExpressionIncDecLValueNormal(f, n, oper, oper2, t, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) postfixExpressionIncDecLValueNormal(f *function, n *cc.PostfixExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
pe := n.PostfixExpression.Operand.Type()
defer p.w("%s", p.convert(n, n.PostfixExpression.Operand, t, flags))
x := "Dec"
if oper == "++" {
x = "Inc"
}
p.w("%sPost%s%s(&", p.task.crt, x, p.helperType(n, pe))
p.postfixExpression(f, n.PostfixExpression, pe, exprLValue, flags)
p.w(", %d)", p.incDelta(n.PostfixExpression, pe))
}
func (p *project) postfixExpressionIncDecVoid(f *function, n *cc.PostfixExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
switch k := p.opKind(f, n, n.Operand.Type()); k {
case opNormal:
p.postfixExpressionIncDecVoidNormal(f, n, oper, oper2, t, mode, flags)
case opBitfield:
p.postfixExpressionIncDec(f, n, oper, oper2, t, exprValue, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) postfixExpressionIncDecVoidNormal(f *function, n *cc.PostfixExpression, oper, oper2 string, t cc.Type, mode exprMode, flags flags) {
if d := n.PostfixExpression.Declarator(); d != nil && p.isVolatileOrAtomic(d) {
switch d.Type().Size() {
case 4, 8:
if !d.Type().IsIntegerType() {
p.err(n, "unsupported volatile declarator type: %v", d.Type())
return
}
if f != nil {
if local := f.locals[d]; local != nil {
if local.isPinned {
panic(todo(""))
}
p.w("atomic.Add%s(&%s, ", p.helperType(n, d.Type()), local.name)
switch oper {
case "++":
// ok
case "--":
p.w("-")
default:
p.err(n, "unsupported volatile declarator operation: %v", oper)
}
p.w("%d)", p.incDelta(n, d.Type()))
return
}
}
if tld := p.tlds[d]; tld != nil {
p.w("atomic.Add%s(&%s, ", p.helperType(n, d.Type()), tld.name)
switch oper {
case "++":
// ok
case "--":
p.w("-")
default:
p.err(n, "unsupported volatile declarator operation: %v", oper)
}
p.w("%d)", p.incDelta(n, d.Type()))
return
}
panic(todo("", n.Position(), d.Position()))
default:
p.err(n, "unsupported volatile declarator size: %v", d.Type().Size())
return
}
}
pe := n.PostfixExpression.Operand.Type().Decay()
p.postfixExpression(f, n.PostfixExpression, pe, exprLValue, flags)
if pe.IsIntegerType() || pe.Kind() == cc.Ptr && p.incDelta(n, pe) == 1 {
p.w("%s", oper)
return
}
switch pe.Kind() {
case cc.Ptr, cc.Float, cc.Double:
p.w("%s %d", oper2, p.incDelta(n, pe))
return
}
panic(todo("", n.Position(), pe, pe.Kind()))
}
func (p *project) incDelta(n cc.Node, t cc.Type) uintptr {
if t.IsArithmeticType() {
return 1
}
if t.Kind() == cc.Ptr || t.Kind() == cc.Array {
return t.Elem().Size()
}
panic(todo("", n.Position(), t.Kind()))
}
func (p *project) bitFldOff(t cc.Type, tok cc.Token) {
var off uintptr
fld, ok := t.FieldByName(tok.Value)
switch {
case ok && !fld.IsBitField():
panic(todo("%v: internal error: bitFdlOff must not be used with non bit fields", origin(2)))
case !ok:
p.err(&tok, "uknown field: %s", tok.Value)
default:
off = fld.BitFieldBlockFirst().Offset()
}
if off != 0 {
p.w("+%d", off)
}
p.w("/* &.%s */", tok.Value)
}
func (p *project) fldOff(t cc.Type, tok cc.Token) {
if t.Kind() == cc.Ptr {
t = t.Elem()
}
var off uintptr
fld, ok := t.FieldByName(tok.Value)
switch {
case ok && fld.IsBitField():
panic(todo("%v: internal error: fdlOff must not be used with bit fields", origin(2)))
case !ok:
p.err(&tok, "uknown field: %s", tok.Value)
default:
off = fld.Offset()
}
if off != 0 {
p.w("+%d", off)
}
p.w("/* &.%s */", tok.Value)
}
func (p *project) postfixExpressionCall(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '(' ArgumentExpressionList ')'
switch mode {
case exprVoid:
p.postfixExpressionCallVoid(f, n, t, mode, flags)
case exprValue:
p.postfixExpressionCallValue(f, n, t, mode, flags)
case exprBool:
p.postfixExpressionCallBool(f, n, t, mode, flags)
default:
panic(todo("", mode))
}
}
func (p *project) postfixExpressionCallBool(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '(' ArgumentExpressionList ')'
p.w("(")
defer p.w(")")
defer p.w(" != 0")
if d := n.PostfixExpression.Declarator(); d != nil {
switch d.Name() {
case idVaArg:
if !f.vaType.IsScalarType() {
panic(todo("", f.vaType))
}
lhs := n.ArgumentExpressionList.AssignmentExpression
p.w("%sVa%s(&", p.task.crt, p.helperType(n, f.vaType))
p.assignmentExpression(f, lhs, lhs.Operand.Type(), exprLValue, flags)
p.w(")")
return
case idAtomicLoadN:
p.atomicLoadN(f, n, t, mode, flags)
return
case idBuiltinConstantPImpl:
p.w("%v", n.Operand.Value())
return
}
}
var va uintptr
if f != nil {
va = f.vaLists[n]
}
p.postfixExpression(f, n.PostfixExpression, n.PostfixExpression.Operand.Type(), exprFunc, flags)
p.argumentExpressionList(f, n.PostfixExpression, n.ArgumentExpressionList, va)
}
func (p *project) postfixExpressionCallValue(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '(' ArgumentExpressionList ')'
defer p.w("%s", p.convert(n, n.Operand, t, flags))
if d := n.PostfixExpression.Declarator(); d != nil {
switch d.Name() {
case idVaEnd:
p.w("_ = ")
arg := n.ArgumentExpressionList.AssignmentExpression
p.assignmentExpression(f, arg, arg.Operand.Type(), exprValue, flags)
return
case idVaStart:
lhs := n.ArgumentExpressionList.AssignmentExpression
p.assignmentExpression(f, lhs, lhs.Operand.Type(), exprLValue, flags)
p.w(" = %s", f.vaName)
return
case idVaArg:
if !f.vaType.IsScalarType() {
panic(todo("", f.vaType))
}
lhs := n.ArgumentExpressionList.AssignmentExpression
p.w("%sVa%s(&", p.task.crt, p.helperType(n, f.vaType))
p.assignmentExpression(f, lhs, lhs.Operand.Type(), exprLValue, flags)
p.w(")")
return
case idAtomicLoadN:
p.atomicLoadN(f, n, t, mode, flags)
return
case idAddOverflow:
p.addOverflow(f, n, t, mode, flags)
return
case idSubOverflow:
p.subOverflow(f, n, t, mode, flags)
return
case idMulOverflow:
p.mulOverflow(f, n, t, mode, flags)
return
case idBuiltinConstantPImpl:
p.w("%v", n.Operand.Value())
return
}
}
var va uintptr
if f != nil {
va = f.vaLists[n]
}
p.postfixExpression(f, n.PostfixExpression, n.PostfixExpression.Operand.Type(), exprFunc, flags)
p.argumentExpressionList(f, n.PostfixExpression, n.ArgumentExpressionList, va)
}
// bool __builtin_mul_overflow (type1 a, type2 b, type3 *res)
func (p *project) mulOverflow(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
args := p.argList(n.ArgumentExpressionList)
if len(args) != 3 {
p.err(n, "expected 3 arguments in call to __builtin_mul_overflow")
return
}
pt := args[2].Operand.Type()
if pt.Kind() != cc.Ptr {
p.err(n, "invalid argument of __builtin_mul_overflow (expected pointer): %s", pt)
return
}
vt := pt.Elem()
switch {
case vt.IsIntegerType():
switch vt.Size() {
case 1, 2, 4, 8, 16:
p.w("%sX__builtin_mul_overflow%s", p.task.crt, p.helperType(n, vt))
default:
p.err(n, "invalid argument of __builtin_mul_overflow: %v, elem kind %v", pt, vt.Kind())
return
}
p.w("(%s", f.tlsName)
types := []cc.Type{vt, vt, pt}
for i, v := range args[:3] {
p.w(", ")
p.assignmentExpression(f, v, types[i], exprValue, flags)
}
p.w(")")
return
}
p.err(n, "invalid arguments of __builtin_mul_overflow: (%v, %v, %v)", args[0].Operand.Type(), args[1].Operand.Type(), args[2].Operand.Type())
}
// bool __builtin_sub_overflow (type1 a, type2 b, type3 *res)
func (p *project) subOverflow(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
args := p.argList(n.ArgumentExpressionList)
if len(args) != 3 {
p.err(n, "expected 3 arguments in call to __builtin_sub_overflow")
return
}
pt := args[2].Operand.Type()
if pt.Kind() != cc.Ptr {
p.err(n, "invalid argument of __builtin_sub_overflow (expected pointer): %s", pt)
return
}
vt := pt.Elem()
switch {
case vt.IsIntegerType():
switch vt.Size() {
case 1, 2, 4, 8:
p.w("%sX__builtin_sub_overflow%s", p.task.crt, p.helperType(n, vt))
default:
p.err(n, "invalid argument of __builtin_sub_overflow: %v, elem kind %v", pt, vt.Kind())
return
}
p.w("(%s", f.tlsName)
types := []cc.Type{vt, vt, pt}
for i, v := range args[:3] {
p.w(", ")
p.assignmentExpression(f, v, types[i], exprValue, flags)
}
p.w(")")
return
}
p.err(n, "invalid arguments of __builtin_sub_overflow: (%v, %v, %v)", args[0].Operand.Type(), args[1].Operand.Type(), args[2].Operand.Type())
}
// bool __builtin_add_overflow (type1 a, type2 b, type3 *res)
func (p *project) addOverflow(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
args := p.argList(n.ArgumentExpressionList)
if len(args) != 3 {
p.err(n, "expected 3 arguments in call to __builtin_add_overflow")
return
}
pt := args[2].Operand.Type()
if pt.Kind() != cc.Ptr {
p.err(n, "invalid argument of __builtin_add_overflow (expected pointer): %s", pt)
return
}
vt := pt.Elem()
switch {
case vt.IsIntegerType():
switch vt.Size() {
case 1, 2, 4, 8:
p.w("%sX__builtin_add_overflow%s", p.task.crt, p.helperType(n, vt))
default:
p.err(n, "invalid argument of __builtin_add_overflow: %v, elem kind %v", pt, vt.Kind())
return
}
p.w("(%s", f.tlsName)
types := []cc.Type{vt, vt, pt}
for i, v := range args[:3] {
p.w(", ")
p.assignmentExpression(f, v, types[i], exprValue, flags)
}
p.w(")")
return
}
p.err(n, "invalid arguments of __builtin_add_overflow: (%v, %v, %v)", args[0].Operand.Type(), args[1].Operand.Type(), args[2].Operand.Type())
}
// type __atomic_load_n (type *ptr, int memorder)
func (p *project) atomicLoadN(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
args := p.argList(n.ArgumentExpressionList)
if len(args) != 2 {
p.err(n, "expected 2 arguments in call to __atomic_load_n")
return
}
pt := args[0].Operand.Type()
if pt.Kind() != cc.Ptr {
p.err(n, "invalid argument of __atomic_load_n (expected pointer): %s", pt)
return
}
vt := pt.Elem()
switch {
case vt.IsIntegerType():
var s, sb string
switch {
case vt.IsSignedType():
s = "Int"
sb = "int8"
default:
s = "Uint"
sb = "byte"
}
switch vt.Size() {
case 1:
switch {
case p.task.ignoreUnsupportedAligment:
p.w("(*(*%s)(unsafe.Pointer(", sb)
p.assignmentExpression(f, args[0], pt, exprValue, flags)
p.w(")))")
default:
p.err(n, "invalid argument of __atomic_load_n: %v, elem kind %v", pt, vt.Kind())
}
return
case 2, 4, 8:
p.w("%sAtomicLoadN%s%d", p.task.crt, s, 8*vt.Size())
default:
p.err(n, "invalid argument of __atomic_load_n: %v, elem kind %v", pt, vt.Kind())
return
}
types := []cc.Type{pt, p.intType}
p.w("(")
for i, v := range args[:2] {
if i != 0 {
p.w(", ")
}
p.assignmentExpression(f, v, types[i], exprValue, flags)
}
p.w(")")
return
case vt.Kind() == cc.Ptr:
panic(todo("", pt, vt))
}
p.err(n, "invalid first argument of __atomic_load_n: %v, elem kind %v", pt, vt.Kind())
}
func (p *project) postfixExpressionCallVoid(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
// PostfixExpression '(' ArgumentExpressionList ')'
if d := n.PostfixExpression.Declarator(); d != nil {
switch d.Name() {
case idVaEnd:
p.w("_ = ")
arg := n.ArgumentExpressionList.AssignmentExpression
p.assignmentExpression(f, arg, arg.Operand.Type(), exprValue, flags)
return
case idVaStart:
lhs := n.ArgumentExpressionList.AssignmentExpression
p.assignmentExpression(f, lhs, lhs.Operand.Type(), exprLValue, flags)
p.w(" = %s", f.vaName)
return
case idVaArg:
if !f.vaType.IsScalarType() {
panic(todo("", f.vaType))
}
lhs := n.ArgumentExpressionList.AssignmentExpression
p.w("%sVa%s(&", p.task.crt, p.helperType(n, f.vaType))
p.assignmentExpression(f, lhs, lhs.Operand.Type(), exprLValue, flags)
p.w(")")
return
case idAtomicStoreN:
p.atomicStoreN(f, n, t, mode, flags)
return
case idMulOverflow:
p.mulOverflow(f, n, t, mode, flags)
return
}
}
var va uintptr
if f != nil {
va = f.vaLists[n]
}
p.postfixExpression(f, n.PostfixExpression, n.PostfixExpression.Operand.Type(), exprFunc, flags)
p.argumentExpressionList(f, n.PostfixExpression, n.ArgumentExpressionList, va)
}
// void __atomic_store_n (type *ptr, type val, int memorder)
func (p *project) atomicStoreN(f *function, n *cc.PostfixExpression, t cc.Type, mode exprMode, flags flags) {
args := p.argList(n.ArgumentExpressionList)
if len(args) != 3 {
p.err(n, "expected 3 arguments in call to __atomic_store_n")
return
}
pt := args[0].Operand.Type()
if pt.Kind() != cc.Ptr {
p.err(n, "invalid first argument of __atomic_store_n (expected pointer): %s", pt)
return
}
vt := args[1].Operand.Type()
switch {
case vt.IsIntegerType():
var s string
switch {
case vt.IsSignedType():
s = "Int"
default:
s = "Uint"
}
switch vt.Size() {
case 2, 4, 8:
p.w("%sAtomicStoreN%s%d", p.task.crt, s, 8*vt.Size())
default:
p.err(n, "invalid arguments of __atomic_store_n: (%v, %v), element kind %v", pt, vt, vt.Kind())
return
}
p.w("(")
types := []cc.Type{pt, vt, p.intType}
for i, v := range args[:3] {
if i != 0 {
p.w(", ")
}
if i == 1 {
p.w("%s(", strings.ToLower(p.helperType(n, vt)))
}
p.assignmentExpression(f, v, types[i], exprValue, flags)
if i == 1 {
p.w(")")
}
}
p.w(")")
return
case vt.Kind() == cc.Ptr:
p.w("%sAtomicStoreNUintptr", p.task.crt)
p.w("(")
types := []cc.Type{pt, vt, p.intType}
for i, v := range args[:3] {
if i != 0 {
p.w(", ")
}
if i == 1 {
p.w("%s(", strings.ToLower(p.helperType(n, vt)))
}
p.assignmentExpression(f, v, types[i], exprValue, flags)
if i == 1 {
p.w(")")
}
}
p.w(")")
return
}
p.err(n, "invalid arguments of __atomic_store_n: (%v, %v), element kind %v", pt, vt, vt.Kind())
}
func (p *project) argList(n *cc.ArgumentExpressionList) (r []*cc.AssignmentExpression) {
for ; n != nil; n = n.ArgumentExpressionList {
r = append(r, n.AssignmentExpression)
}
return r
}
func (p *project) argumentExpressionList(f *function, pe *cc.PostfixExpression, n *cc.ArgumentExpressionList, bpOff uintptr) {
switch {
case f == nil:
p.w("(nil")
default:
p.w("(%s", f.tlsName)
}
ft := funcType(pe.Operand.Type())
isVariadic := ft.IsVariadic()
params := ft.Parameters()
if len(params) == 1 && params[0].Type().Kind() == cc.Void {
params = nil
}
var args []*cc.AssignmentExpression
for ; n != nil; n = n.ArgumentExpressionList {
args = append(args, n.AssignmentExpression)
}
if len(args) < len(params) {
panic(todo("", p.pos(n)))
}
va := true
if len(args) > len(params) && !isVariadic {
var a []string
for _, v := range args {
a = append(a, v.Operand.Type().String())
}
sargs := strings.Join(a, ",")
switch d := pe.Declarator(); {
case d == nil:
p.err(pe, "too many arguments (%s) in call to %s", sargs, ft)
default:
p.err(pe, "too many arguments (%s) in call to %s of type %s", sargs, d.Name(), ft)
}
va = false
}
paren := ""
for i, arg := range args {
p.w(",%s", tidyComment(" ", arg))
mode := exprValue
if at := arg.Operand.Type(); at.Kind() == cc.Array {
mode = exprDecay
}
switch {
case i < len(params):
switch pt := params[i].Type(); {
case isTransparentUnion(params[i].Type()):
p.callArgTransparentUnion(f, arg, pt)
default:
p.assignmentExpression(f, arg, arg.Promote(), mode, 0)
}
case va && i == len(params):
p.w("%sVaList(%s%s, ", p.task.crt, f.bpName, nonZeroUintptr(bpOff))
paren = ")"
fallthrough
default:
var flags flags
if arg.Promote().IsIntegerType() {
switch x := arg.Operand.Value().(type) {
case cc.Int64Value:
if x < mathutil.MinInt || x > mathutil.MaxInt {
flags |= fForceConv
}
case cc.Uint64Value:
if x > mathutil.MaxInt {
flags |= fForceConv
}
}
}
p.assignmentExpression(f, arg, arg.Promote(), mode, flags)
}
}
if isVariadic && len(args) == len(params) {
p.w(", 0")
}
p.w("%s)", paren)
}
// https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Type-Attributes.html
//
// transparent_union
//
// This attribute, attached to a union type definition, indicates that any
// function parameter having that union type causes calls to that function to
// be treated in a special way.
//
// First, the argument corresponding to a transparent union type can be of any
// type in the union; no cast is required. Also, if the union contains a
// pointer type, the corresponding argument can be a null pointer constant or a
// void pointer expression; and if the union contains a void pointer type, the
// corresponding argument can be any pointer expression. If the union member
// type is a pointer, qualifiers like const on the referenced type must be
// respected, just as with normal pointer conversions.
//
// Second, the argument is passed to the function using the calling conventions
// of first member of the transparent union, not the calling conventions of the
// union itself. All members of the union must have the same machine
// representation; this is necessary for this argument passing to work
// properly.
//
// Transparent unions are designed for library functions that have multiple
// interfaces for compatibility reasons. For example, suppose the wait function
// must accept either a value of type int * to comply with Posix, or a value of
// type union wait * to comply with the 4.1BSD interface. If wait's parameter
// were void *, wait would accept both kinds of arguments, but it would also
// accept any other pointer type and this would make argument type checking
// less useful. Instead, <sys/wait.h> might define the interface as follows:
//
// typedef union
// {
// int *__ip;
// union wait *__up;
// } wait_status_ptr_t __attribute__ ((__transparent_union__));
//
// pid_t wait (wait_status_ptr_t);
//
// This interface allows either int * or union wait * arguments to be passed,
// using the int * calling convention. The program can call wait with arguments
// of either type:
//
// int w1 () { int w; return wait (&w); }
// int w2 () { union wait w; return wait (&w); }
//
// With this interface, wait's implementation might look like this:
//
// pid_t wait (wait_status_ptr_t p)
// {
// return waitpid (-1, p.__ip, 0);
// }
func (p *project) callArgTransparentUnion(f *function, n *cc.AssignmentExpression, pt cc.Type) {
if pt.Kind() != cc.Union {
panic(todo("internal error"))
}
ot := n.Operand.Type()
switch k := pt.UnionCommon(); k {
case cc.Ptr:
if ot.Kind() != k {
panic(todo("", n.Position(), k, pt))
}
p.assignmentExpression(f, n, ot, exprValue, 0)
default:
panic(todo("", n.Position(), k, pt))
}
}
func isTransparentUnion(t cc.Type) (r bool) {
for _, v := range attrs(t) {
cc.Inspect(v, func(n cc.Node, _ bool) bool {
if x, ok := n.(*cc.AttributeValue); ok && x.Token.Value == idTransparentUnion {
r = true
return false
}
return true
})
}
return r
}
func attrs(t cc.Type) []*cc.AttributeSpecifier {
if a := t.Attributes(); len(a) != 0 {
return a
}
if t.IsAliasType() {
if a := t.Alias().Attributes(); len(a) != 0 {
return a
}
return t.AliasDeclarator().Type().Attributes()
}
return nil
}
func (p *project) nzUintptr(n cc.Node, f func(), op cc.Operand) {
if op.Type().IsIntegerType() {
switch {
case op.IsZero():
return
case op.Value() != nil:
switch x := op.Value().(type) {
case cc.Int64Value:
if x > 0 && uint64(x) <= 1<<(8*p.ptrSize)-1 {
p.w("+%d", x)
return
}
case cc.Uint64Value:
if uint64(x) <= 1<<(8*p.ptrSize)-1 {
p.w("+%d", x)
return
}
}
p.w(" +%sUintptrFrom%s(", p.task.crt, p.helperType(n, op.Type()))
default:
p.w(" +uintptr(")
}
f()
p.w(")")
return
}
panic(todo("", p.pos(n)))
}
func (p *project) primaryExpression(f *function, n *cc.PrimaryExpression, t cc.Type, mode exprMode, flags flags) {
switch mode {
case exprLValue:
p.primaryExpressionLValue(f, n, t, mode, flags)
case exprValue:
p.primaryExpressionValue(f, n, t, mode, flags)
case exprFunc:
p.primaryExpressionFunc(f, n, t, mode, flags)
case exprAddrOf:
p.primaryExpressionAddrOf(f, n, t, mode, flags)
case exprSelect:
p.primaryExpressionSelect(f, n, t, mode, flags)
case exprPSelect:
p.primaryExpressionPSelect(f, n, t, mode, flags)
case exprBool:
p.primaryExpressionBool(f, n, t, mode, flags)
case exprVoid:
p.primaryExpressionVoid(f, n, t, mode, flags)
case exprDecay:
p.primaryExpressionDecay(f, n, t, mode, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) primaryExpressionDecay(f *function, n *cc.PrimaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PrimaryExpressionIdent: // IDENTIFIER
switch d := n.Declarator(); {
case d != nil:
p.declarator(n, f, d, t, mode, flags)
default:
panic(todo("", p.pos(n)))
}
case cc.PrimaryExpressionInt: // INTCONST
p.intConst(n, n.Token.Src.String(), n.Operand, t, flags)
case cc.PrimaryExpressionFloat: // FLOATCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionEnum: // ENUMCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionChar: // CHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionLChar: // LONGCHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionString: // STRINGLITERAL
p.w("%s", p.stringLiteral(n.Operand.Value()))
case cc.PrimaryExpressionLString: // LONGSTRINGLITERAL
p.w("%s", p.wideStringLiteral(n.Operand.Value(), 0))
case cc.PrimaryExpressionExpr: // '(' Expression ')'
p.expression(f, n.Expression, t, mode, flags)
case cc.PrimaryExpressionStmt: // '(' CompoundStatement ')'
p.err(n, "statement expressions not supported")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) primaryExpressionVoid(f *function, n *cc.PrimaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PrimaryExpressionIdent: // IDENTIFIER
p.w("_ = ")
p.primaryExpression(f, n, n.Operand.Type(), exprValue, flags)
case cc.PrimaryExpressionInt, // INTCONST
cc.PrimaryExpressionFloat, // FLOATCONST
cc.PrimaryExpressionEnum, // ENUMCONST
cc.PrimaryExpressionChar, // CHARCONST
cc.PrimaryExpressionLChar, // LONGCHARCONST
cc.PrimaryExpressionString, // STRINGLITERAL
cc.PrimaryExpressionLString: // LONGSTRINGLITERAL
// nop
case cc.PrimaryExpressionExpr: // '(' Expression ')'
p.expression(f, n.Expression, n.Expression.Operand.Type(), mode, flags)
case cc.PrimaryExpressionStmt: // '(' CompoundStatement ')'
p.compoundStatement(f, n.CompoundStatement, "", true, false, 0)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) primaryExpressionBool(f *function, n *cc.PrimaryExpression, t cc.Type, mode exprMode, flags flags) {
if n.Case != cc.PrimaryExpressionExpr {
p.w("(")
defer p.w(")")
}
if n.Case != cc.PrimaryExpressionExpr {
defer p.w(" != 0")
}
switch n.Case {
case cc.PrimaryExpressionIdent: // IDENTIFIER
switch d := n.Declarator(); {
case d != nil:
p.declarator(n, f, d, d.Type(), exprValue, flags)
default:
panic(todo("", p.pos(n)))
}
case cc.PrimaryExpressionInt: // INTCONST
p.intConst(n, n.Token.Src.String(), n.Operand, n.Operand.Type(), flags)
case cc.PrimaryExpressionFloat: // FLOATCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionEnum: // ENUMCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionChar: // CHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionLChar: // LONGCHARCONST
p.charConst(n, n.Token.Src.String(), n.Operand, t, flags)
case cc.PrimaryExpressionString: // STRINGLITERAL
p.w(" 1 ")
case cc.PrimaryExpressionLString: // LONGSTRINGLITERAL
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionExpr: // '(' Expression ')'
p.w("(")
defer p.w(")")
p.expression(f, n.Expression, t, mode, flags)
case cc.PrimaryExpressionStmt: // '(' CompoundStatement ')'
p.w("func() %v {", p.typ(n, n.CompoundStatement.Operand.Type()))
p.compoundStatement(f, n.CompoundStatement, "", true, false, exprValue)
p.w("}()")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) primaryExpressionPSelect(f *function, n *cc.PrimaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PrimaryExpressionIdent: // IDENTIFIER
switch d := n.Declarator(); {
case d != nil:
switch k := p.declaratorKind(d); k {
case opArray:
panic(todo("", p.pos(n)))
p.primaryExpression(f, n, t, exprDecay, flags)
default:
p.declarator(n, f, d, t, mode, flags)
}
default:
panic(todo("", p.pos(n)))
}
case cc.PrimaryExpressionInt: // INTCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionFloat: // FLOATCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionEnum: // ENUMCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionChar: // CHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionLChar: // LONGCHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionString: // STRINGLITERAL
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionLString: // LONGSTRINGLITERAL
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionExpr: // '(' Expression ')'
p.expression(f, n.Expression, t, mode, flags)
case cc.PrimaryExpressionStmt: // '(' CompoundStatement ')'
p.err(n, "statement expressions not supported")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) primaryExpressionSelect(f *function, n *cc.PrimaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PrimaryExpressionIdent: // IDENTIFIER
switch d := n.Declarator(); {
case d != nil:
p.declarator(n, f, d, t, mode, flags)
default:
panic(todo("", p.pos(n)))
}
case cc.PrimaryExpressionInt: // INTCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionFloat: // FLOATCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionEnum: // ENUMCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionChar: // CHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionLChar: // LONGCHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionString: // STRINGLITERAL
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionLString: // LONGSTRINGLITERAL
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionExpr: // '(' Expression ')'
p.expression(f, n.Expression, t, mode, flags)
case cc.PrimaryExpressionStmt: // '(' CompoundStatement ')'
p.err(n, "statement expressions not supported")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) primaryExpressionAddrOf(f *function, n *cc.PrimaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PrimaryExpressionIdent: // IDENTIFIER
switch d := n.Declarator(); {
case d != nil:
p.declarator(n, f, d, t, mode, flags)
default:
panic(todo("", p.pos(n)))
}
case cc.PrimaryExpressionInt: // INTCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionFloat: // FLOATCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionEnum: // ENUMCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionChar: // CHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionLChar: // LONGCHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionString: // STRINGLITERAL
p.w("%s", p.stringLiteral(n.Operand.Value()))
case cc.PrimaryExpressionLString: // LONGSTRINGLITERAL
p.w("%s", p.wideStringLiteral(n.Operand.Value(), 0))
case cc.PrimaryExpressionExpr: // '(' Expression ')'
p.expression(f, n.Expression, t, mode, flags)
case cc.PrimaryExpressionStmt: // '(' CompoundStatement ')'
p.err(n, "statement expressions not supported")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) primaryExpressionFunc(f *function, n *cc.PrimaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PrimaryExpressionIdent: // IDENTIFIER
p.fnVal(n, f, func() { p.primaryExpression(f, n, n.Operand.Type(), exprValue, flags) }, n.Declarator(), n.Operand.Type(), 0, mode, flags)
case cc.PrimaryExpressionInt: // INTCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionFloat: // FLOATCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionEnum: // ENUMCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionChar: // CHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionLChar: // LONGCHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionString: // STRINGLITERAL
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionLString: // LONGSTRINGLITERAL
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionExpr: // '(' Expression ')'
p.expression(f, n.Expression, t, mode, flags)
case cc.PrimaryExpressionStmt: // '(' CompoundStatement ')'
p.err(n, "statement expressions not supported")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func cmpNormalizeValue(v cc.Value) cc.Value {
switch x := v.(type) {
case cc.Int64Value:
if x >= 0 {
return cc.Uint64Value(x)
}
}
return v
}
func (p *project) primaryExpressionValue(f *function, n *cc.PrimaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PrimaryExpressionIdent: // IDENTIFIER
switch d := n.Declarator(); {
case d != nil:
p.declarator(n, f, d, t, mode, flags)
default:
panic(todo("", p.pos(n)))
}
case cc.PrimaryExpressionInt: // INTCONST
if m := n.Token.Macro(); m != 0 {
if d := p.defines[m]; d.name != "" {
if cmpNormalizeValue(n.Operand.Value()) == cmpNormalizeValue(d.value) {
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w(" %s ", d.name)
break
}
p.w("/* %s */", m)
}
}
p.intConst(n, n.Token.Src.String(), n.Operand, t, flags)
case cc.PrimaryExpressionFloat: // FLOATCONST
//TODO use #define
p.floatConst(n, n.Token.Src.String(), n.Operand, t, flags)
case cc.PrimaryExpressionEnum: // ENUMCONST
en := n.ResolvedTo().(*cc.Enumerator)
if n.ResolvedIn().Parent() == nil {
if nm := p.enumConsts[en.Token.Value]; nm != "" {
p.w(" %s ", nm)
break
}
}
p.intConst(n, "", n.Operand, t, flags)
p.w("/* %s */", en.Token.Value)
case cc.PrimaryExpressionChar: // CHARCONST
p.charConst(n, n.Token.Src.String(), n.Operand, t, flags)
case cc.PrimaryExpressionLChar: // LONGCHARCONST
p.charConst(n, n.Token.Src.String(), n.Operand, t, flags)
case cc.PrimaryExpressionString: // STRINGLITERAL
p.w("%s", p.stringLiteral(n.Operand.Value()))
case cc.PrimaryExpressionLString: // LONGSTRINGLITERAL
p.w("%s", p.wideStringLiteral(n.Operand.Value(), 0))
case cc.PrimaryExpressionExpr: // '(' Expression ')'
p.w("(")
defer p.w(")")
p.expression(f, n.Expression, t, mode, flags)
case cc.PrimaryExpressionStmt: // '(' CompoundStatement ')'
p.statementExpression(f, n.CompoundStatement, t, mode, flags)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) statementExpression(f *function, n *cc.CompoundStatement, t cc.Type, mode exprMode, flags flags) {
defer p.w("%s", p.convert(n, n.Operand, t, flags))
p.w(" func() %v {", p.typ(n, n.Operand.Type()))
p.compoundStatement(f, n, "", true, false, mode)
p.w("}()")
}
func (p *project) primaryExpressionLValue(f *function, n *cc.PrimaryExpression, t cc.Type, mode exprMode, flags flags) {
switch n.Case {
case cc.PrimaryExpressionIdent: // IDENTIFIER
switch d := n.Declarator(); {
case d != nil:
p.declarator(n, f, d, t, mode, flags)
default:
panic(todo("", p.pos(n)))
}
case cc.PrimaryExpressionInt: // INTCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionFloat: // FLOATCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionEnum: // ENUMCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionChar: // CHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionLChar: // LONGCHARCONST
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionString: // STRINGLITERAL
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionLString: // LONGSTRINGLITERAL
panic(todo("", p.pos(n)))
case cc.PrimaryExpressionExpr: // '(' Expression ')'
p.w("(")
defer p.w(")")
p.expression(f, n.Expression, t, mode, flags)
case cc.PrimaryExpressionStmt: // '(' CompoundStatement ')'
p.err(n, "statement expressions not supported")
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) stringLiteralString(s string) string {
if p.pass1 {
return ""
}
id := cc.String(s)
off, ok := p.tsOffs[id]
if !ok {
off = uintptr(p.ts.Len())
p.ts.WriteString(s)
p.ts.WriteByte(0)
p.tsOffs[id] = off
}
return fmt.Sprintf("(%s%s)%s", p.tsNameP, nonZeroUintptr(off), p.stringSnippet(s))
}
func (p *project) stringLiteral(v cc.Value) string {
if p.pass1 {
return ""
}
switch x := v.(type) {
case cc.StringValue:
id := cc.StringID(x)
off, ok := p.tsOffs[id]
s := id.String()
if !ok {
off = uintptr(p.ts.Len())
p.ts.WriteString(s)
p.ts.WriteByte(0)
p.tsOffs[id] = off
}
return fmt.Sprintf("(%s%s)%s", p.tsNameP, nonZeroUintptr(off), p.stringSnippet(s))
default:
panic(todo("%T", x))
}
}
func (p *project) stringSnippet(s string) string {
s = strings.ReplaceAll(s, "*/", "*\\/")
const max = 16
switch {
case len(s) <= max:
return fmt.Sprintf("/* %q */", s)
default:
return fmt.Sprintf("/* %q */", s[:16]+"...")
}
}
func (p *project) wideStringLiteral(v cc.Value, pad int) string {
if p.pass1 {
return ""
}
switch x := v.(type) {
case cc.WideStringValue:
id := cc.StringID(x)
off, ok := p.tsWOffs[id]
if !ok {
off = p.wcharSize * uintptr(len(p.tsW))
s := []rune(id.String())
if pad != 0 {
s = append(s, make([]rune, pad)...)
}
p.tsW = append(p.tsW, s...)
p.tsW = append(p.tsW, 0)
p.tsWOffs[id] = off
}
return fmt.Sprintf("(%s%s)", p.tsWNameP, nonZeroUintptr(off))
default:
panic(todo("%T", x))
}
}
func (p *project) charConst(n cc.Node, src string, op cc.Operand, to cc.Type, flags flags) {
switch {
case to.IsArithmeticType():
defer p.w("%s", p.convert(n, op, to, flags))
case to.Kind() == cc.Ptr && op.IsZero():
p.w(" 0 ")
return
default:
panic(todo("%v: t %v, to %v, to.Alias() %v", n.Position(), op.Type(), to, to.Alias()))
}
r, mb, _, err := strconv.UnquoteChar(src[1:len(src)-1], '\'')
rValid := !mb && err == nil
var on uint64
switch x := op.Value().(type) {
case cc.Int64Value:
on = uint64(x)
case cc.Uint64Value:
on = uint64(x)
default:
panic(todo("%T(%v)", x, x))
}
var mask uint64
switch {
case !to.IsIntegerType():
// ok
if rValid { // Prefer original form
p.w("%s", src)
return
}
p.w("%d", on)
return
case to.IsSignedType():
var in int64
var ok bool
switch to.Size() {
case 1:
in = int64(int8(on))
ok = int8(on) >= 0
case 2:
in = int64(int16(on))
ok = int16(on) >= 0
case 4:
in = int64(int32(on))
ok = int32(on) >= 0
case 8:
in = int64(int64(on))
ok = in >= 0
default:
panic(todo("", op.Type().Size()))
}
if ok && rValid && uint64(in) == on { // Prefer original form
p.w("%s", src)
return
}
p.w("%d", in)
default:
switch to.Size() {
case 1:
mask = 0xff
case 2:
mask = 0xffff
case 4:
mask = 0xffffffff
case 8:
mask = 0xffffffffffffffff
default:
panic(todo("", op.Type().Size()))
}
if rValid && uint64(r)&mask == on { // Prefer original form
p.w("%s", src)
return
}
p.w("%d", on&mask)
}
}
func (p *project) floatConst(n cc.Node, src string, op cc.Operand, to cc.Type, flags flags) {
if flags&fForceRuntimeConv != 0 {
p.w("%s(", p.helperType2(n, op.Type(), to))
defer p.w(")")
}
bits := 64
switch to.Kind() {
case cc.Float:
bits = 32
}
src = strings.TrimRight(src, "flFL")
sn, err := strconv.ParseFloat(src, bits)
snValid := err == nil
switch x := op.Value().(type) {
case cc.Float64Value:
switch to.Kind() {
case cc.Double:
if snValid && sn == float64(x) { // Prefer original form.
p.w("%s", src)
return
}
p.w("math.Float64frombits(%#x)", math.Float64bits(float64(x)))
case cc.Float:
if snValid && float32(sn) == float32(x) { // Prefer original form.
p.w("%s", src)
return
}
p.w("math.Float32frombits(%#x)", math.Float32bits(float32(x)))
default:
defer p.w("%s", p.convert(n, op, to, 0))
if snValid && sn == float64(x) { // Prefer original form.
p.w("%s", src)
return
}
p.w("math.Float64frombits(%#x)", math.Float64bits(float64(x)))
}
case cc.Float32Value:
switch to.Kind() {
case cc.Double:
if snValid && float32(sn) == float32(x) { // Prefer original form.
p.w("%s", src)
return
}
p.w("math.Float64frombits(%#x)", math.Float64bits(float64(x)))
case cc.Float:
if snValid && float32(sn) == float32(x) { // Prefer original form.
p.w("%s", src)
return
}
p.w("math.Float32frombits(%#x)", math.Float32bits(float32(x)))
default:
if to.IsIntegerType() {
if s := p.float2Int(n, x, to); s != "" {
defer p.w("%s%s", s, p.convertType(n, op.Type(), to, 0))
break
}
}
defer p.w("%s", p.convert(n, op, to, 0))
if snValid && float32(sn) == float32(x) { // Prefer original form.
p.w("%s", src)
return
}
p.w("math.Float32frombits(%#x)", math.Float32bits(float32(x)))
}
default:
panic(todo("%T(%v)", x, x))
}
}
func (p *project) float2Int(n cc.Node, x cc.Float32Value, to cc.Type) string {
switch {
case to.IsSignedType():
limits := &signedSaturationLimits[to.Size()]
v := float64(x)
switch {
case math.IsNaN(v):
panic(todo("", p.pos(n)))
case math.IsInf(v, -1):
panic(todo("", p.pos(n)))
case math.IsInf(v, 1):
panic(todo("", p.pos(n)))
case v < limits.fmin:
return fmt.Sprint(limits.min)
case v > limits.fmax:
return fmt.Sprint(limits.max)
}
default:
limits := &unsignedSaturationLimits[to.Size()]
v := float64(x)
switch {
case math.IsNaN(v):
panic(todo("", p.pos(n)))
case math.IsInf(v, -1):
panic(todo("", p.pos(n)))
case math.IsInf(v, 1):
panic(todo("", p.pos(n)))
case v < 0:
return "0"
case v > limits.fmax:
return fmt.Sprint(limits.max)
}
}
return ""
}
type signedSaturationLimit struct {
fmin, fmax float64
min, max int64
}
type unsignedSaturationLimit struct {
fmax float64
max uint64
}
var (
signedSaturationLimits = [...]signedSaturationLimit{
1: {math.Nextafter(math.MinInt32, 0), math.Nextafter(math.MaxInt32, 0), math.MinInt32, math.MaxInt32},
2: {math.Nextafter(math.MinInt32, 0), math.Nextafter(math.MaxInt32, 0), math.MinInt32, math.MaxInt32},
4: {math.Nextafter(math.MinInt32, 0), math.Nextafter(math.MaxInt32, 0), math.MinInt32, math.MaxInt32},
8: {math.Nextafter(math.MinInt64, 0), math.Nextafter(math.MaxInt64, 0), math.MinInt64, math.MaxInt64},
}
unsignedSaturationLimits = [...]unsignedSaturationLimit{
1: {math.Nextafter(math.MaxUint32, 0), math.MaxUint32},
2: {math.Nextafter(math.MaxUint32, 0), math.MaxUint32},
4: {math.Nextafter(math.MaxUint32, 0), math.MaxUint32},
8: {math.Nextafter(math.MaxUint64, 0), math.MaxUint64},
}
)
func (p *project) intConst(n cc.Node, src string, op cc.Operand, to cc.Type, flags flags) {
ptr := to.Kind() == cc.Ptr
switch {
case to.IsArithmeticType():
// p.w("/*10568 %T(%#[1]x) %v -> %v */", op.Value(), op.Type(), to) //TODO-
if flags&fForceNoConv != 0 {
break
}
if !op.Type().IsSignedType() && op.Type().Size() == 8 && op.Value().(cc.Uint64Value) > math.MaxInt64 {
flags |= fForceRuntimeConv
}
defer p.w("%s", p.convert(n, op, to, flags))
case ptr:
p.w(" uintptr(")
defer p.w(")")
// ok
default:
panic(todo("%v: %v -> %v", p.pos(n), op.Type(), to))
}
src = strings.TrimRight(src, "luLU")
sn, err := strconv.ParseUint(src, 0, 64)
snValid := err == nil
var on uint64
switch x := op.Value().(type) {
case cc.Int64Value:
if x < 0 {
sn, err := strconv.ParseInt(src, 0, 64)
snValid := err == nil
if snValid && sn == int64(x) { // Prefer original form
p.w("%s", src)
return
}
p.w("%d", x)
return
}
on = uint64(x)
case cc.Uint64Value:
on = uint64(x)
default:
panic(todo("%T(%v)", x, x))
}
if snValid && sn == on { // Prefer original form
p.w("%s", src)
return
}
p.w("%d", on)
}
func (p *project) assignShiftOp(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, oper, oper2 string, flags flags) {
// UnaryExpression "<<=" AssignmentExpression etc.
switch mode {
case exprVoid:
p.assignShiftOpVoid(f, n, t, mode, oper, oper2, flags)
default:
panic(todo("", mode))
}
}
func (p *project) assignShiftOpVoid(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, oper, oper2 string, flags flags) {
// UnaryExpression "<<=" AssignmentExpression etc.
switch k := p.opKind(f, n.UnaryExpression, n.UnaryExpression.Operand.Type()); k {
case opNormal:
p.assignShiftOpVoidNormal(f, n, t, mode, oper, oper2, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) assignShiftOpVoidNormal(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, oper, oper2 string, flags flags) {
switch {
case n.Operand.Type().IsBitFieldType():
panic(todo("", p.pos(n)))
default:
if d := n.UnaryExpression.Declarator(); d != nil {
switch d.Type().Kind() {
case cc.Int128, cc.UInt128:
p.declarator(n, f, d, d.Type(), exprLValue, flags)
p.w(".LValue%s(", oper2)
p.assignmentExpression(f, n.AssignmentExpression, p.intType, exprValue, flags)
p.w(")")
return
default:
p.declarator(n, f, d, d.Type(), exprLValue, flags)
p.w(" %s= ", oper)
p.assignmentExpression(f, n.AssignmentExpression, n.Promote(), exprValue, flags)
return
}
}
lhs := n.UnaryExpression
switch {
case lhs.Operand.Type().IsArithmeticType():
p.w("%sAssign%sPtr%s(", p.task.crt, oper2, p.helperType(n, lhs.Operand.Type()))
p.unaryExpression(f, lhs, lhs.Operand.Type(), exprAddrOf, flags)
p.w(", int(")
p.assignmentExpression(f, n.AssignmentExpression, n.Promote(), exprValue, flags)
p.w("))")
default:
panic(todo("", p.pos(n), lhs.Operand.Type()))
}
}
}
func (p *project) assignOp(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, oper, oper2 string, flags flags) {
// UnaryExpression "*=" AssignmentExpression etc.
switch mode {
case exprVoid:
p.assignOpVoid(f, n, t, mode, oper, oper2, flags)
case exprValue, exprCondReturn:
p.assignOpValue(f, n, t, mode, oper, oper2, flags)
default:
panic(todo("", n.Position(), mode))
}
}
func (p *project) assignOpValue(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, oper, oper2 string, flags flags) {
// UnaryExpression "*=" AssignmentExpression etc.
switch k := p.opKind(f, n.UnaryExpression, n.UnaryExpression.Operand.Type()); k {
case opNormal:
p.assignOpValueNormal(f, n, t, oper, oper2, mode, flags)
case opBitfield:
p.assignOpValueBitfield(f, n, t, oper, oper2, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) assignOpValueBitfield(f *function, n *cc.AssignmentExpression, t cc.Type, oper, oper2 string, mode exprMode, flags flags) {
// UnaryExpression "*=" AssignmentExpression etc.
asInt := oper2 == "Shl" || oper2 == "Shr"
if asInt {
panic(todo(""))
}
ot := n.Operand.Type()
lhs := n.UnaryExpression
bf := lhs.Operand.Type().BitField()
defer p.w("%s", p.convertType(n, ot, t, flags))
p.w(" func() %v {", p.typ(n, ot))
switch lhs.Case {
case cc.UnaryExpressionPostfix: // PostfixExpression
pe := n.UnaryExpression.PostfixExpression
switch pe.Case {
case cc.PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER
p.w("__p := ")
p.postfixExpression(f, pe, pe.Operand.Type(), exprAddrOf, flags)
p.w("; __v := ")
p.readBitfield(lhs, "__p", bf, ot)
p.w(" %s (", oper)
p.assignmentExpression(f, n.AssignmentExpression, ot, exprValue, flags)
p.w("); return %sAssignBitFieldPtr%d%s(__p, __v, %d, %d, %#x)", p.task.crt, bf.BitFieldBlockWidth(), p.bfHelperType(ot), bf.BitFieldWidth(), bf.BitFieldOffset(), bf.Mask())
case cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
panic(todo("", p.pos(n)))
default:
panic(todo("", n.Position(), pe.Case))
}
default:
panic(todo("", n.Position(), lhs.Case))
}
p.w("}()")
}
func (p *project) readBitfield(n cc.Node, ptr string, bf cc.Field, promote cc.Type) {
bw := bf.BitFieldBlockWidth()
m := bf.Mask()
o := bf.BitFieldOffset()
w := bf.BitFieldWidth()
p.w("(%s(*(*uint%d)(unsafe.Pointer(%s))&%#x)", p.typ(n, promote), bw, ptr, m)
switch {
case bf.Type().IsSignedType():
bits := int(promote.Size()) * 8
p.w("<<%d>>%d)", bits-w-o, bits-w)
default:
p.w(">>%d)", o)
}
}
func (p *project) assignOpValueNormal(f *function, n *cc.AssignmentExpression, t cc.Type, oper, oper2 string, mode exprMode, flags flags) {
if mode == exprCondReturn {
p.w("return ")
}
asInt := oper2 == "Shl" || oper2 == "Shr"
lhs := n.UnaryExpression
// UnaryExpression "*=" AssignmentExpression etc.
if d := lhs.Declarator(); d != nil {
if local := f.locals[d]; local != nil && local.isPinned {
switch {
case lhs.Operand.Type().IsArithmeticType():
defer p.w("%s", p.convertType(n, lhs.Operand.Type(), t, flags))
p.w("%sAssign%sPtr%s(", p.task.crt, oper2, p.helperType(n, lhs.Operand.Type()))
p.unaryExpression(f, lhs, lhs.Operand.Type(), exprAddrOf, flags)
p.w(", ")
if asInt {
p.w("int(")
}
p.assignmentExpression(f, n.AssignmentExpression, lhs.Operand.Type(), exprValue, flags)
if asInt {
p.w(")")
}
p.w(")")
default:
panic(todo("", lhs.Operand.Type()))
}
return
}
switch {
case d.Type().Kind() == cc.Ptr:
defer p.w("%s", p.convertType(n, d.Type(), t, flags))
p.w("%sAssign%s%s(&", p.task.crt, oper2, p.helperType(n, d.Type()))
p.declarator(n, f, d, d.Type(), exprLValue, flags)
p.w(", ")
if dd := p.incDelta(d, d.Type()); dd != 1 {
p.w("%d*(", dd)
defer p.w(")")
}
p.assignmentExpression(f, n.AssignmentExpression, d.Type(), exprValue, flags)
p.w(")")
case d.Type().IsArithmeticType():
defer p.w("%s", p.convertType(n, d.Type(), t, flags))
p.w("%sAssign%s%s(&", p.task.crt, oper2, p.helperType(n, d.Type()))
p.declarator(n, f, d, d.Type(), exprLValue, flags)
p.w(", ")
if asInt {
p.w("int(")
}
p.assignmentExpression(f, n.AssignmentExpression, d.Type(), exprValue, flags)
p.w(")")
if asInt {
p.w(")")
}
default:
panic(todo("", p.pos(n), p.pos(d), d.Name()))
}
return
}
switch {
case lhs.Operand.Type().IsArithmeticType():
defer p.w("%s", p.convertType(n, lhs.Operand.Type(), t, flags))
p.w("%sAssign%sPtr%s(", p.task.crt, oper2, p.helperType(n, lhs.Operand.Type()))
p.unaryExpression(f, lhs, lhs.Operand.Type(), exprAddrOf, flags)
p.w(", ")
if asInt {
p.w("int(")
}
p.assignmentExpression(f, n.AssignmentExpression, lhs.Operand.Type(), exprValue, flags)
if asInt {
p.w(")")
}
p.w(")")
default:
panic(todo("", lhs.Operand.Type()))
}
}
func (p *project) assignOpVoid(f *function, n *cc.AssignmentExpression, t cc.Type, mode exprMode, oper, oper2 string, flags flags) {
// UnaryExpression "*=" AssignmentExpression etc.
switch k := p.opKind(f, n.UnaryExpression, n.UnaryExpression.Operand.Type()); k {
case opNormal:
p.assignOpVoidNormal(f, n, t, oper, oper2, mode, flags)
case opBitfield:
p.assignOpVoidBitfield(f, n, t, oper, oper2, mode, flags)
case opArrayParameter:
p.assignOpVoidArrayParameter(f, n, t, oper, oper2, mode, flags)
default:
panic(todo("", n.Position(), k))
}
}
func (p *project) assignOpVoidArrayParameter(f *function, n *cc.AssignmentExpression, t cc.Type, oper, oper2 string, mode exprMode, flags flags) {
// UnaryExpression "*=" AssignmentExpression etc.
if oper != "+" && oper != "-" {
panic(todo("", p.pos(n)))
}
d := n.UnaryExpression.Declarator()
switch local := f.locals[d]; {
case local != nil && local.isPinned:
p.w("*(*uintptr)(unsafe.Pointer(%s%s))", f.bpName, nonZeroUintptr(local.off))
default:
p.declarator(n, f, d, d.Type(), exprLValue, flags)
}
p.w(" %s= ", oper)
if dd := p.incDelta(d, d.Type()); dd != 1 {
p.w("%d*", dd)
}
p.w("uintptr(")
p.assignmentExpression(f, n.AssignmentExpression, n.AssignmentExpression.Operand.Type(), exprValue, flags)
p.w(")")
}
func (p *project) assignOpVoidBitfield(f *function, n *cc.AssignmentExpression, t cc.Type, oper, oper2 string, mode exprMode, flags flags) {
// UnaryExpression "*=" AssignmentExpression etc.
lhs := n.UnaryExpression
lt := lhs.Operand.Type()
switch lhs.Case {
case cc.UnaryExpressionPostfix: // PostfixExpression
pe := n.UnaryExpression.PostfixExpression
switch pe.Case {
case cc.PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER
bf := lt.BitField()
p.w("%sSetBitFieldPtr%d%s(", p.task.crt, bf.BitFieldBlockWidth(), p.bfHelperType(n.Promote()))
p.unaryExpression(f, lhs, lt, exprAddrOf, flags)
p.w(", (")
s := p.convertType(n, lt, n.Promote(), flags)
p.unaryExpression(f, lhs, lt, exprValue, flags)
p.w(")%s %s ", s, oper)
s = p.convertType(n, lt, n.Promote(), flags)
p.assignmentExpression(f, n.AssignmentExpression, n.Promote(), exprValue, flags)
p.w("%s", s)
p.w(", %d, %#x)", bf.BitFieldOffset(), bf.Mask())
case cc.PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER
switch d := pe.PostfixExpression.Declarator(); {
case d != nil:
panic(todo("", p.pos(n)))
default:
panic(todo("", p.pos(n)))
}
default:
panic(todo("", n.Position(), pe.Case))
}
default:
panic(todo("", n.Position(), lhs.Case))
}
}
func (p *project) assignOpVoidNormal(f *function, n *cc.AssignmentExpression, t cc.Type, oper, oper2 string, mode exprMode, flags flags) {
// UnaryExpression "*=" AssignmentExpression etc.
rop := n.AssignmentExpression.Operand
if d := n.UnaryExpression.Declarator(); d != nil {
if local := f.locals[d]; local != nil && local.isPinned {
if p.isVolatileOrAtomic(d) {
panic(todo(""))
}
p.declarator(n, f, d, d.Type(), exprLValue, flags)
switch {
case d.Type().Kind() == cc.Ptr:
p.w(" %s= ", oper)
if dd := p.incDelta(d, d.Type()); dd != 1 {
p.w("%d*(", dd)
defer p.w(")")
}
defer p.w("%s", p.convert(n, rop.ConvertTo(n.Promote()), d.Type(), flags))
p.assignmentExpression(f, n.AssignmentExpression, n.Promote(), exprValue, flags)
case d.Type().IsArithmeticType():
p.w(" %s= ", oper)
defer p.w("%s", p.convert(n, rop.ConvertTo(n.Promote()), d.Type(), flags))
p.assignmentExpression(f, n.AssignmentExpression, n.Promote(), exprValue, flags)
default:
panic(todo("", n.Position(), d.Type().Kind()))
}
return
}
if p.isVolatileOrAtomic(d) {
var local *local
var tld *tld
var nm string
if f != nil {
if local = f.locals[d]; local != nil {
nm = local.name
}
}
if local == nil {
if tld = p.tlds[d]; tld == nil {
p.err(n, "%v: internal error (%v: %v)", n.Position(), d.Position(), d.Name())
return
}
nm = tld.name
}
var sign string
switch oper {
case "-":
sign = oper
fallthrough
case "+":
sz := d.Type().Size()
var ht string
switch sz {
case 4, 8:
if !d.Type().IsScalarType() {
p.err(n, "unsupported volatile declarator type: %v", d.Type())
break
}
ht = p.helperType(n, d.Type())
default:
p.err(n, "unsupported volatile declarator size: %v", sz)
return
}
if local != nil {
if local.isPinned {
panic(todo(""))
}
}
p.w("%sAtomicAdd%s(&%s, %s%s(", p.task.crt, ht, nm, sign, p.typ(n, d.Type()))
p.assignmentExpression(f, n.AssignmentExpression, n.Promote(), exprValue, flags)
p.w("))")
return
default:
p.warn(n, "unsupported volatile declarator operation: %v", oper)
p.w("%s = ", nm)
defer p.w("%s", p.convert(n, rop.ConvertTo(n.Promote()), d.Type(), flags))
p.declarator(n, f, d, n.Promote(), exprValue, flags)
p.w(" %s (", oper)
p.assignmentExpression(f, n.AssignmentExpression, n.Promote(), exprValue, flags)
p.w(")")
return
}
}
p.declarator(n, f, d, d.Type(), exprLValue, flags)
switch d.Type().Kind() {
case cc.Ptr:
if oper != "+" && oper != "-" {
panic(todo("", p.pos(n)))
}
p.w(" %s= ", oper)
if dd := p.incDelta(d, d.Type()); dd != 1 {
p.w("%d*(", dd)
defer p.w(")")
}
defer p.w("%s", p.convert(n, rop.ConvertTo(n.Promote()), d.Type(), flags))
p.assignmentExpression(f, n.AssignmentExpression, n.Promote(), exprValue, flags)
case cc.Int128, cc.UInt128:
p.w(" = ")
p.declarator(n, f, d, n.Promote(), exprValue, flags)
p.w(".%s(", oper2)
p.assignmentExpression(f, n.AssignmentExpression, n.Promote(), exprValue, flags)
p.w(")")
default:
p.w(" = ")
defer p.w("%s", p.convert(n, rop.ConvertTo(n.Promote()), d.Type(), flags))
p.declarator(n, f, d, n.Promote(), exprValue, flags)
p.w(" %s (", oper)
p.assignmentExpression(f, n.AssignmentExpression, n.Promote(), exprValue, flags)
p.w(")")
}
return
}
lhs := n.UnaryExpression
switch {
case lhs.Operand.Type().IsArithmeticType():
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, lhs.Operand.Type()))
p.unaryExpression(f, lhs, lhs.Operand.Type(), exprAddrOf, flags)
p.w(")) %s= ", oper)
defer p.w("%s", p.convert(n, rop.ConvertTo(n.Promote()), lhs.Operand.Type(), flags))
p.w("(")
p.assignmentExpression(f, n.AssignmentExpression, n.Promote(), exprValue, flags)
p.w(")")
case lhs.Operand.Type().Kind() == cc.Ptr:
p.w("*(*%s)(unsafe.Pointer(", p.typ(n, lhs.Operand.Type()))
p.unaryExpression(f, lhs, lhs.Operand.Type(), exprAddrOf, flags)
p.w(")) %s= (", oper)
p.assignmentExpression(f, n.AssignmentExpression, lhs.Operand.Type(), exprValue, flags)
p.w(")")
if dd := p.incDelta(n, lhs.Operand.Type()); dd != 1 {
p.w("*%d", dd)
}
default:
panic(todo("", lhs.Operand.Type()))
}
}
func (p *project) warn(n cc.Node, s string, args ...interface{}) {
s = fmt.Sprintf(s, args...)
s = strings.TrimRight(s, "\t\n\r")
fmt.Fprintf(os.Stderr, "%v: warning: %s\n", n.Position(), s)
}
func (p *project) iterationStatement(f *function, n *cc.IterationStatement) {
sv := f.switchCtx
sv2 := f.continueCtx
sv3 := f.breakCtx
f.switchCtx = 0
f.continueCtx = 0
f.breakCtx = 0
defer func() {
f.breakCtx = sv3
f.continueCtx = sv2
f.switchCtx = sv
}()
p.w("%s", tidyComment("\n", n))
switch n.Case {
case cc.IterationStatementWhile: // "while" '(' Expression ')' Statement
if f.hasJumps {
// a: if !expr goto b
// stmt
// goto a
// b:
a := f.flatLabel()
b := f.flatLabel()
f.continueCtx = a
f.breakCtx = b
p.w("__%d: if !(", a)
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprBool, 0)
p.w(") { goto __%d };", b)
p.statement(f, n.Statement, false, false, false, 0)
p.w("; goto __%d; __%d:", a, b)
break
}
p.w("for ")
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprBool, 0)
p.statement(f, n.Statement, true, false, false, 0)
case cc.IterationStatementDo: // "do" Statement "while" '(' Expression ')' ';'
if f.hasJumps {
// a: stmt
// b: if expr goto a // b is the continue label
// c:
a := f.flatLabel()
b := f.flatLabel()
c := f.flatLabel()
f.continueCtx = b
f.breakCtx = c
p.w("__%d:", a)
p.statement(f, n.Statement, false, false, false, 0)
p.w(";goto __%d; __%[1]d: if ", b)
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprBool, 0)
p.w("{goto __%d};goto __%d;__%[2]d:", a, c)
break
}
v := "__ccgo"
if !p.pass1 {
v = f.scope.take(cc.String(v))
}
p.w("for %v := true; %[1]v; %[1]v = ", v)
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprBool, 0)
p.statement(f, n.Statement, true, false, false, 0)
case cc.IterationStatementFor: // "for" '(' Expression ';' Expression ';' Expression ')' Statement
if f.hasJumps || n.Expression3 != nil && n.Expression3.Case == cc.ExpressionComma {
// expr
// a: if !expr2 goto c
// stmt
// b: expr3 // label for continue
// goto a
// c:
a := f.flatLabel()
b := f.flatLabel()
f.continueCtx = b
c := f.flatLabel()
f.breakCtx = c
if n.Expression != nil {
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprVoid, fNoCondAssignment)
}
semi := ""
if n.Expression != nil || n.Expression2 != nil || n.Expression3 != nil {
semi = ";"
}
p.w("%s__%d:", semi, a)
if n.Expression2 != nil {
p.w("if !(")
p.expression(f, n.Expression2, n.Expression2.Operand.Type(), exprBool, 0)
p.w(") { goto __%d }", c)
}
p.w("%s", semi)
p.statement(f, n.Statement, false, false, false, 0)
p.w(";goto __%d; __%[1]d:", b)
if n.Expression3 != nil {
p.expression(f, n.Expression3, n.Expression3.Operand.Type(), exprVoid, fNoCondAssignment)
}
p.w("%sgoto __%d; goto __%d;__%[3]d:", semi, a, c)
break
}
expr := true
if n.Expression != nil && n.Expression.Case == cc.ExpressionComma {
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprVoid, 0)
p.w(";")
expr = false
}
p.w("for ")
if expr && n.Expression != nil {
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprVoid, fNoCondAssignment)
}
p.w("; ")
if n.Expression2 != nil {
p.expression(f, n.Expression2, n.Expression2.Operand.Type(), exprBool, 0)
}
p.w("; ")
if n.Expression3 != nil {
p.expression(f, n.Expression3, n.Expression3.Operand.Type(), exprVoid, fNoCondAssignment)
}
p.statement(f, n.Statement, true, false, false, 0)
case cc.IterationStatementForDecl: // "for" '(' Declaration Expression ';' Expression ')' Statement
if !(f.hasJumps || n.Expression2 != nil && n.Expression2.Case == cc.ExpressionComma) {
p.w("{")
p.declaration(f, n.Declaration, false)
p.w("for ;")
if n.Expression != nil {
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprBool, 0)
}
p.w(";")
if n.Expression2 != nil {
p.expression(f, n.Expression2, n.Expression2.Operand.Type(), exprVoid, fNoCondAssignment)
}
p.w("{")
p.statement(f, n.Statement, false, true, false, 0)
p.w("}};")
break
}
var ids []*cc.InitDeclarator
for list := n.Declaration.InitDeclaratorList; list != nil; list = list.InitDeclaratorList {
ids = append(ids, list.InitDeclarator)
}
// declaration
// a: if !expr goto c
// stmt
// b: expr2 // label for continue
// goto a
// c:
a := f.flatLabel()
b := f.flatLabel()
f.continueCtx = b
c := f.flatLabel()
f.breakCtx = c
p.w("{")
p.declaration(f, n.Declaration, false)
p.w(";")
p.w("__%d:", a)
if n.Expression != nil {
p.w("if !(")
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprBool, 0)
p.w(") { goto __%d }", c)
}
p.w(";")
p.statement(f, n.Statement, false, false, false, 0)
p.w(";goto __%d; __%[1]d:", b)
if n.Expression2 != nil {
p.expression(f, n.Expression2, n.Expression2.Operand.Type(), exprVoid, fNoCondAssignment)
}
p.w("; goto __%d; goto __%d;__%[2]d:\n}", a, c)
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) selectionStatement(f *function, n *cc.SelectionStatement) {
p.w("%s", tidyComment("\n", n))
switch n.Case {
case cc.SelectionStatementIf: // "if" '(' Expression ')' Statement
sv := f.ifCtx
f.ifCtx = n
defer func() { f.ifCtx = sv }()
if f.hasJumps {
// if !expr goto a
// stmt
// a:
f.ifCtx = n
a := f.flatLabel()
p.w("if !(")
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprBool, 0)
p.w(") { goto __%d };", a)
p.statement(f, n.Statement, false, false, false, 0)
p.w(";__%d: ", a)
break
}
p.w("if ")
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprBool, 0)
p.statement(f, n.Statement, true, false, false, 0)
case cc.SelectionStatementIfElse: // "if" '(' Expression ')' Statement "else" Statement
sv := f.ifCtx
f.ifCtx = n
defer func() { f.ifCtx = sv }()
if f.hasJumps {
// if !expr goto a
// stmt
// goto b
// a:
// stmt2
// b:
a := f.flatLabel()
b := f.flatLabel()
p.w("if !(")
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprBool, 0)
p.w(") { goto __%d };", a)
p.statement(f, n.Statement, false, false, false, 0)
p.w(";goto __%d; __%d:", b, a)
p.statement(f, n.Statement2, false, false, false, 0)
p.w(";__%d:", b)
break
}
p.w("if ")
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprBool, 0)
p.statement(f, n.Statement, true, false, false, 0)
p.w(" else ")
switch {
case p.isIfStmt(n.Statement2):
p.statement(f, n.Statement2, false, true, false, 0)
default:
p.statement(f, n.Statement2, true, false, false, 0)
}
case cc.SelectionStatementSwitch: // "switch" '(' Expression ')' Statement
// just dont generate in this case
if f.switchCtx == inSwitchFirst {
break
}
sv := f.switchCtx
sb := f.block
sc := p.pauseCodegen
svBreakCtx := f.breakCtx
f.breakCtx = 0
f.block = f.blocks[n.Statement.CompoundStatement]
defer func() {
f.block = sb
f.switchCtx = sv
f.breakCtx = svBreakCtx
p.pauseCodegen = sc
}()
if f.hasJumps {
f.switchCtx = inSwitchFlat
p.flatSwitch(f, n)
break
}
f.switchCtx = inSwitchFirst
// fmt.Println(f.block.decls)
if len(f.block.decls) != 0 {
f.block.topDecl = true
// fmt.Printf("%p:%tf\n", f.block, f.block.topDecl)
p.w("{")
for _, v := range f.block.decls {
// fmt.Printf("%p:%tf\n", f.block, f.block.topDecl)
p.declaration(f, v, true)
// fmt.Println("done!")
}
}
p.w("switch ")
p.expression(f, n.Expression, n.Promote(), exprValue, 0)
p.pauseCodegen = true
p.statement(f, n.Statement, true, false, true, 0)
p.pauseCodegen = false
if len(f.block.decls) != 0 {
p.w("}")
}
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
}
func (p *project) isIfStmt(n *cc.Statement) bool {
if n.Case != cc.StatementSelection {
return false
}
switch n.SelectionStatement.Case {
case cc.SelectionStatementIf, cc.SelectionStatementIfElse:
return true
}
return false
}
func (p *project) flatSwitch(f *function, n *cc.SelectionStatement) {
if n.Statement.Case != cc.StatementCompound {
panic(todo("", p.pos(n)))
}
sv := f.block
f.block = f.blocks[n.Statement.CompoundStatement]
defer func() { f.block = sv }()
// "switch" '(' Expression ')' Statement
cases := n.Cases()
labels := map[*cc.LabeledStatement]int{}
svBreakCtx := f.breakCtx
f.breakCtx = f.flatLabel()
p.w("switch ")
p.expression(f, n.Expression, n.Promote(), exprValue, 0)
p.w("{")
for _, ls := range cases {
switch ls.Case {
case cc.LabeledStatementLabel: // IDENTIFIER ':' AttributeSpecifierList Statement
continue
case cc.LabeledStatementCaseLabel: // "case" ConstantExpression ':' Statement
p.w("%scase ", tidyComment("\n", ls))
p.constantExpression(f, ls.ConstantExpression, ls.ConstantExpression.Operand.Type(), exprValue, 0)
p.w(":")
case cc.LabeledStatementDefault: // "default" ':' Statement
p.w("%sdefault:", tidyComment("\n", ls))
case cc.LabeledStatementRange: // "case" ConstantExpression "..." ConstantExpression ':' Statement
panic(todo("", p.pos(n)))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
label := f.flatLabel()
labels[ls] = label
p.w("goto __%d;", label)
}
p.w("}; goto __%d;", f.breakCtx)
svLabels := f.flatSwitchLabels
f.flatSwitchLabels = labels
p.statement(f, n.Statement, false, true, false, 0)
f.flatSwitchLabels = svLabels
p.w("__%d:", f.breakCtx)
f.breakCtx = svBreakCtx
}
func (p *project) expressionStatement(f *function, n *cc.ExpressionStatement) {
p.w("%s", tidyComment("\n", n))
// Expression AttributeSpecifierList ';'
if n.Expression == nil {
return
}
p.expression(f, n.Expression, n.Expression.Operand.Type(), exprVoid, 0)
}
func (p *project) labeledStatement(f *function, n *cc.LabeledStatement) (r *cc.JumpStatement) {
if f.hasJumps { //TODO merge with ...Flat below
return p.labeledStatementFlat(f, n)
}
switch n.Case {
case cc.LabeledStatementLabel: // IDENTIFIER ':' AttributeSpecifierList Statement
if _, ok := f.unusedLabels[n.Token.Value]; ok {
p.w("goto %s;", f.labelNames[n.Token.Value])
}
p.w("%s%s:", comment("\n", n), f.labelNames[n.Token.Value])
r = p.statement(f, n.Statement, false, false, false, 0)
case
cc.LabeledStatementCaseLabel, // "case" ConstantExpression ':' Statement
cc.LabeledStatementDefault: // "default" ':' Statement
p.labeledStatementCase(f, n)
case cc.LabeledStatementRange: // "case" ConstantExpression "..." ConstantExpression ':' Statement
panic(todo("", n.Position(), n.Case))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
return r
}
func (p *project) labeledStatementFlat(f *function, n *cc.LabeledStatement) (r *cc.JumpStatement) {
switch n.Case {
case cc.LabeledStatementLabel: // IDENTIFIER ':' AttributeSpecifierList Statement
if _, ok := f.unusedLabels[n.Token.Value]; ok {
p.w("goto %s;", f.labelNames[n.Token.Value])
}
p.w("%s%s:", tidyComment("\n", n), f.labelNames[n.Token.Value])
r = p.statement(f, n.Statement, false, false, false, 0)
case
cc.LabeledStatementCaseLabel, // "case" ConstantExpression ':' Statement
cc.LabeledStatementDefault: // "default" ':' Statement
p.labeledStatementCase(f, n)
case cc.LabeledStatementRange: // "case" ConstantExpression "..." ConstantExpression ':' Statement
panic(todo("", n.Position(), n.Case))
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
return r
}
func (p *project) labeledStatementCase(f *function, n *cc.LabeledStatement) {
switch f.switchCtx {
case inSwitchFirst:
f.switchCtx = inSwitchCase
p.pauseCodegen = false
case inSwitchCase:
p.w("\nfallthrough;")
case inSwitchSeenBreak:
f.switchCtx = inSwitchCase
case inSwitchFlat:
// ok
default:
panic(todo("", n.Position(), f.switchCtx))
}
switch n.Case {
case cc.LabeledStatementCaseLabel: // "case" ConstantExpression ':' Statement
switch {
case f.switchCtx == inSwitchFlat:
p.w("%s__%d:", tidyComment("\n", n), f.flatSwitchLabels[n])
default:
p.w("%scase ", tidyComment("\n", n))
p.constantExpression(f, n.ConstantExpression, n.ConstantExpression.Operand.Type(), exprValue, 0)
p.w(":")
}
case cc.LabeledStatementDefault: // "default" ':' Statement
switch {
case f.switchCtx == inSwitchFlat:
p.w("%s__%d:", tidyComment("\n", n), f.flatSwitchLabels[n])
default:
p.w("%sdefault:", tidyComment("\n", n))
}
default:
panic(todo("%v: internal error: %v", n.Position(), n.Case))
}
p.statement(f, n.Statement, false, false, false, 0)
}
func (p *project) constantExpression(f *function, n *cc.ConstantExpression, t cc.Type, mode exprMode, flags flags) {
// ConditionalExpression
p.conditionalExpression(f, n.ConditionalExpression, t, mode, flags)
}
func (p *project) functionDefinitionSignature(n cc.Node, f *function, tld *tld) {
switch {
case f.mainSignatureForced:
p.w("%sfunc %s(%s *%sTLS, _ int32, _ uintptr) int32", tidyComment("\n", f.fndef), tld.name, f.tlsName, p.task.crt)
default:
p.w("%s", tidyComment("\n", f.fndef))
p.functionSignature(n, f, f.fndef.Declarator.Type(), tld.name)
}
}
func (p *project) functionSignature2(n cc.Node, f *function, t cc.Type, nm string) {
p.w("func %s", nm)
p.w("(_ *%sTLS", p.task.crt)
suffix := 1
for _, v := range t.Parameters() {
if v.Type().Kind() == cc.Void {
break
}
pn := "_"
if d := v.Declarator(); d != nil {
pn = d.Name().String()
if _, ok := reservedNames[pn]; ok {
pn += strconv.Itoa(suffix)
suffix++
}
}
p.w(", %s %s", pn, p.paramTyp(v.Declarator(), v.Type()))
}
if t.IsVariadic() {
p.w(", _ /* va_list */ uintptr")
}
p.w(")")
if rt := t.Result(); rt != nil && rt.Kind() != cc.Void {
p.w(" %s", p.typ(n, rt))
}
}
func (p *project) functionSignature(n cc.Node, f *function, t cc.Type, nm string) {
p.w("func")
if nm != "" {
p.w(" %s", nm)
}
switch {
case f == nil || nm == "":
p.w("(*%sTLS", p.task.crt)
default:
p.w("(%s *%sTLS", f.tlsName, p.task.crt)
}
for _, v := range t.Parameters() {
if v.Type().Kind() == cc.Void {
break
}
var pn string
if f != nil && nm != "" {
pn = "_"
if d := v.Declarator(); d != nil {
if local := f.locals[d]; local != nil {
pn = local.name
}
}
}
p.w(", %s %s", pn, p.paramTyp(v.Declarator(), v.Type()))
}
if t.IsVariadic() {
switch {
case f == nil || nm == "":
p.w(", uintptr")
default:
p.w(", %s uintptr", f.vaName)
}
}
p.w(")")
if rt := t.Result(); rt != nil && rt.Kind() != cc.Void {
p.w(" %s", p.typ(n, rt))
}
}
func (p *project) paramTyp(n cc.Node, t cc.Type) string {
if t.Kind() == cc.Array {
return "uintptr"
}
if isTransparentUnion(t) {
switch k := t.UnionCommon(); k {
case cc.Ptr:
return "uintptr"
default:
panic(todo("%v: %v %k", n, t, k))
}
}
return p.typ(n, t)
}
func (p *project) dbg(a ...interface{}) {
p.w("/*DBG.%v %v */", a, origin(2))
}
func (p *project) fnVal(n cc.Node, f *function, expr func(), exprDecl *cc.Declarator, exprType cc.Type, deref int, mode exprMode, flags flags) {
// C type Go type
// fn N/A: produce name from exprDecl
// (*)() func()
// (**)() *func()
if deref < 0 || deref > 1 {
panic(todo(""))
}
switch exprType.Kind() {
case cc.Function:
// C: fn
switch deref {
case 0:
p.declarator(n, f, exprDecl, exprType, mode, flags)
default:
panic(todo("", n.Position()))
}
case cc.Ptr:
switch et := exprType.Elem(); et.Kind() {
case cc.Function:
// C: (*)()
switch deref {
case 0:
// (*struct{ f func()})(unsafe.Pointer(&struct{uintptr}{fprintfptr})).f()
p.w("(*struct{ f ")
p.functionSignature(n, f, et, "")
p.w("})(unsafe.Pointer(&struct{uintptr}{")
expr()
p.w("})).f")
default:
p.declarator(n, f, exprDecl, et, mode, flags)
}
case cc.Ptr:
switch et2 := et.Elem(); et2.Kind() {
case cc.Function:
// C: (**)()
switch deref {
case 0:
panic(todo("", n.Position()))
default:
// (*struct{ f func()})(unsafe.Pointer(&struct{uintptr}{fprintfptr})).f()
p.w("(*(**struct{ f ")
p.functionSignature(n, f, et2, "")
p.w("})(unsafe.Pointer(&struct{uintptr}{")
expr()
p.w("}))).f")
}
default:
panic(todo("", n.Position(), et2.Kind(), deref))
}
default:
panic(todo("", n.Position(), et.Kind(), deref))
}
default:
panic(todo("", n.Position(), exprType.Kind(), deref))
}
}